made with requirebin
Created
May 22, 2017 16:45
-
-
Save davidguttman/ed4ed18399995451cb6b4d3c06ce544b to your computer and use it in GitHub Desktop.
requirebin sketch
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
var Simplex = require('perlin-simplex') | |
var Delaunator = require('delaunator') | |
var getDistance = require('euclidean-distance') | |
var simplex = new Simplex() | |
var SPEED = 0.001 | |
var N_POINTS = 200 | |
document.body.style.background = 'rgb(20, 20, 20)' | |
var stage = createStage() | |
document.body.appendChild(stage) | |
var points = createPoints(N_POINTS) | |
var triangles = createTrianges(points) | |
stage.appendChild(triangles.el) | |
window.requestAnimationFrame(updateLoop) | |
function updateLoop () { | |
window.requestAnimationFrame(updateLoop) | |
points.forEach(function (point) { point.update() }) | |
triangles.update(points) | |
} | |
function createPoints (n) { | |
var points = [] | |
for (var i = 0; i < n; i++) { | |
points.push({ | |
x: Math.random(), | |
y: Math.random(), | |
theta: Math.random() * 2 * Math.PI, | |
update: updatePoint | |
}) | |
} | |
return points | |
} | |
function updatePoint () { | |
var nx = this.x * 5 | |
var ny = this.y * 10 | |
var nz = Date.now() / 1000 | |
var s = simplex.noise3d(nx, ny, nz) | |
var theta = s * 2 * Math.PI | |
this.theta = (0.01 * theta) + (0.99 * this.theta) | |
this.x += SPEED * Math.cos(this.theta) | |
this.y += SPEED * Math.sin(this.theta) | |
this.x = mod(this.x, 1) | |
this.y = mod(this.y, 1) | |
} | |
function createTrianges (points) { | |
var viewBox = [0, 0, 1, 1].join(' ') | |
var pathData = createPathData(points) | |
var parent = document.createElement('div') | |
parent.style.width = '100%' | |
parent.style.height = '100%' | |
parent.innerHTML = ` | |
<svg xmlns='http://www.w3.org/svg/2000' | |
viewBox='${viewBox}' | |
width='100%' | |
height='100%' | |
stroke='none' | |
fill='none'> | |
${pathData} | |
</svg> | |
` | |
var svg = parent.children[0] | |
return { | |
el: parent, | |
update: function (points) { | |
svg.innerHTML = createPathData(points) | |
} | |
} | |
} | |
function createPathData (points) { | |
var coords = points.map(function (point) { | |
return [point.x, point.y] | |
}) | |
var triangles = new Delaunator(coords).triangles | |
var pathData = [] | |
for (var i = 0; i < triangles.length; i += 3) { | |
pathData.push(createTrianglePath( | |
coords[triangles[i + 0]], | |
coords[triangles[i + 1]], | |
coords[triangles[i + 2]] | |
)) | |
} | |
return pathData.join('\n') | |
} | |
function createTrianglePath (pa, pb, pc) { | |
var x0 = pa[0] | |
var y0 = pa[1] | |
var x1 = pb[0] | |
var y1 = pb[1] | |
var x2 = pc[0] | |
var y2 = pc[1] | |
var d = [ | |
'M', x0, y0, | |
'L', x1, y1, | |
'L', x2, y2, | |
'L', x0, y0 | |
].join(' ') | |
var eq = equalness(x0, y0, x1, y1, x2, y2) | |
eq = eq * eq | |
var b = Math.floor(30 + (eq * 130)) | |
var fill = `rgb(${b}, ${b}, ${b})` | |
return `<path d='${d}' fill='${fill}' stroke='none' />` | |
} | |
function equalness (x0, y0, x1, y1, x2, y2) { | |
var a = getDistance([x0, y0], [x1, y1]) | |
var b = getDistance([x0, y0], [x2, y2]) | |
var c = getDistance([x2, y2], [x1, y1]) | |
var diff = Math.abs(a - b) + Math.abs(a - c) + Math.abs(b - c) | |
return 1 - (diff / (a + b + c)) | |
} | |
function createStage (w, h) { | |
var stage = document.createElement('div') | |
stage.style.position = 'absolute' | |
stage.style.top = '10%' | |
stage.style.left = '10%' | |
stage.style.width = '80%' | |
stage.style.height = '80%' | |
return stage | |
} | |
function mod (a, n) { | |
return ((a % n) + n) % n | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
setTimeout(function(){ | |
;require=(function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({"perlin-simplex":[function(require,module,exports){ | |
// https://gist.github.com/banksean/304522 | |
// | |
// Ported from Stefan Gustavson's java implementation | |
// http://staffwww.itn.liu.se/~stegu/simplexnoise/simplexnoise.pdf | |
// Read Stefan's excellent paper for details on how this code works. | |
// | |
// Sean McCullough [email protected] | |
/** | |
* You can pass in a random number generator object if you like. | |
* It is assumed to have a random() method. | |
*/ | |
module.exports = SimplexNoise = function(r) { | |
if (r == undefined) r = Math; | |
this.grad3 = [[1,1,0],[-1,1,0],[1,-1,0],[-1,-1,0], | |
[1,0,1],[-1,0,1],[1,0,-1],[-1,0,-1], | |
[0,1,1],[0,-1,1],[0,1,-1],[0,-1,-1]]; | |
this.p = []; | |
for (var i=0; i<256; i++) { | |
this.p[i] = Math.floor(r.random()*256); | |
} | |
// To remove the need for index wrapping, double the permutation table length | |
this.perm = []; | |
for(var i=0; i<512; i++) { | |
this.perm[i]=this.p[i & 255]; | |
} | |
// A lookup table to traverse the simplex around a given point in 4D. | |
// Details can be found where this table is used, in the 4D noise method. | |
this.simplex = [ | |
[0,1,2,3],[0,1,3,2],[0,0,0,0],[0,2,3,1],[0,0,0,0],[0,0,0,0],[0,0,0,0],[1,2,3,0], | |
[0,2,1,3],[0,0,0,0],[0,3,1,2],[0,3,2,1],[0,0,0,0],[0,0,0,0],[0,0,0,0],[1,3,2,0], | |
[0,0,0,0],[0,0,0,0],[0,0,0,0],[0,0,0,0],[0,0,0,0],[0,0,0,0],[0,0,0,0],[0,0,0,0], | |
[1,2,0,3],[0,0,0,0],[1,3,0,2],[0,0,0,0],[0,0,0,0],[0,0,0,0],[2,3,0,1],[2,3,1,0], | |
[1,0,2,3],[1,0,3,2],[0,0,0,0],[0,0,0,0],[0,0,0,0],[2,0,3,1],[0,0,0,0],[2,1,3,0], | |
[0,0,0,0],[0,0,0,0],[0,0,0,0],[0,0,0,0],[0,0,0,0],[0,0,0,0],[0,0,0,0],[0,0,0,0], | |
[2,0,1,3],[0,0,0,0],[0,0,0,0],[0,0,0,0],[3,0,1,2],[3,0,2,1],[0,0,0,0],[3,1,2,0], | |
[2,1,0,3],[0,0,0,0],[0,0,0,0],[0,0,0,0],[3,1,0,2],[0,0,0,0],[3,2,0,1],[3,2,1,0]]; | |
}; | |
SimplexNoise.prototype.dot = function(g, x, y) { | |
return g[0]*x + g[1]*y; | |
}; | |
SimplexNoise.prototype.noise = function(xin, yin) { | |
var n0, n1, n2; // Noise contributions from the three corners | |
// Skew the input space to determine which simplex cell we're in | |
var F2 = 0.5*(Math.sqrt(3.0)-1.0); | |
var s = (xin+yin)*F2; // Hairy factor for 2D | |
var i = Math.floor(xin+s); | |
var j = Math.floor(yin+s); | |
var G2 = (3.0-Math.sqrt(3.0))/6.0; | |
var t = (i+j)*G2; | |
var X0 = i-t; // Unskew the cell origin back to (x,y) space | |
var Y0 = j-t; | |
var x0 = xin-X0; // The x,y distances from the cell origin | |
var y0 = yin-Y0; | |
// For the 2D case, the simplex shape is an equilateral triangle. | |
// Determine which simplex we are in. | |
var i1, j1; // Offsets for second (middle) corner of simplex in (i,j) coords | |
if(x0>y0) {i1=1; j1=0;} // lower triangle, XY order: (0,0)->(1,0)->(1,1) | |
else {i1=0; j1=1;} // upper triangle, YX order: (0,0)->(0,1)->(1,1) | |
// A step of (1,0) in (i,j) means a step of (1-c,-c) in (x,y), and | |
// a step of (0,1) in (i,j) means a step of (-c,1-c) in (x,y), where | |
// c = (3-sqrt(3))/6 | |
var x1 = x0 - i1 + G2; // Offsets for middle corner in (x,y) unskewed coords | |
var y1 = y0 - j1 + G2; | |
var x2 = x0 - 1.0 + 2.0 * G2; // Offsets for last corner in (x,y) unskewed coords | |
var y2 = y0 - 1.0 + 2.0 * G2; | |
// Work out the hashed gradient indices of the three simplex corners | |
var ii = i & 255; | |
var jj = j & 255; | |
var gi0 = this.perm[ii+this.perm[jj]] % 12; | |
var gi1 = this.perm[ii+i1+this.perm[jj+j1]] % 12; | |
var gi2 = this.perm[ii+1+this.perm[jj+1]] % 12; | |
// Calculate the contribution from the three corners | |
var t0 = 0.5 - x0*x0-y0*y0; | |
if(t0<0) n0 = 0.0; | |
else { | |
t0 *= t0; | |
n0 = t0 * t0 * this.dot(this.grad3[gi0], x0, y0); // (x,y) of grad3 used for 2D gradient | |
} | |
var t1 = 0.5 - x1*x1-y1*y1; | |
if(t1<0) n1 = 0.0; | |
else { | |
t1 *= t1; | |
n1 = t1 * t1 * this.dot(this.grad3[gi1], x1, y1); | |
} | |
var t2 = 0.5 - x2*x2-y2*y2; | |
if(t2<0) n2 = 0.0; | |
else { | |
t2 *= t2; | |
n2 = t2 * t2 * this.dot(this.grad3[gi2], x2, y2); | |
} | |
// Add contributions from each corner to get the final noise value. | |
// The result is scaled to return values in the interval [-1,1]. | |
return 70.0 * (n0 + n1 + n2); | |
}; | |
// 3D simplex noise | |
SimplexNoise.prototype.noise3d = function(xin, yin, zin) { | |
var n0, n1, n2, n3; // Noise contributions from the four corners | |
// Skew the input space to determine which simplex cell we're in | |
var F3 = 1.0/3.0; | |
var s = (xin+yin+zin)*F3; // Very nice and simple skew factor for 3D | |
var i = Math.floor(xin+s); | |
var j = Math.floor(yin+s); | |
var k = Math.floor(zin+s); | |
var G3 = 1.0/6.0; // Very nice and simple unskew factor, too | |
var t = (i+j+k)*G3; | |
var X0 = i-t; // Unskew the cell origin back to (x,y,z) space | |
var Y0 = j-t; | |
var Z0 = k-t; | |
var x0 = xin-X0; // The x,y,z distances from the cell origin | |
var y0 = yin-Y0; | |
var z0 = zin-Z0; | |
// For the 3D case, the simplex shape is a slightly irregular tetrahedron. | |
// Determine which simplex we are in. | |
var i1, j1, k1; // Offsets for second corner of simplex in (i,j,k) coords | |
var i2, j2, k2; // Offsets for third corner of simplex in (i,j,k) coords | |
if(x0>=y0) { | |
if(y0>=z0) | |
{ i1=1; j1=0; k1=0; i2=1; j2=1; k2=0; } // X Y Z order | |
else if(x0>=z0) { i1=1; j1=0; k1=0; i2=1; j2=0; k2=1; } // X Z Y order | |
else { i1=0; j1=0; k1=1; i2=1; j2=0; k2=1; } // Z X Y order | |
} | |
else { // x0<y0 | |
if(y0<z0) { i1=0; j1=0; k1=1; i2=0; j2=1; k2=1; } // Z Y X order | |
else if(x0<z0) { i1=0; j1=1; k1=0; i2=0; j2=1; k2=1; } // Y Z X order | |
else { i1=0; j1=1; k1=0; i2=1; j2=1; k2=0; } // Y X Z order | |
} | |
// A step of (1,0,0) in (i,j,k) means a step of (1-c,-c,-c) in (x,y,z), | |
// a step of (0,1,0) in (i,j,k) means a step of (-c,1-c,-c) in (x,y,z), and | |
// a step of (0,0,1) in (i,j,k) means a step of (-c,-c,1-c) in (x,y,z), where | |
// c = 1/6. | |
var x1 = x0 - i1 + G3; // Offsets for second corner in (x,y,z) coords | |
var y1 = y0 - j1 + G3; | |
var z1 = z0 - k1 + G3; | |
var x2 = x0 - i2 + 2.0*G3; // Offsets for third corner in (x,y,z) coords | |
var y2 = y0 - j2 + 2.0*G3; | |
var z2 = z0 - k2 + 2.0*G3; | |
var x3 = x0 - 1.0 + 3.0*G3; // Offsets for last corner in (x,y,z) coords | |
var y3 = y0 - 1.0 + 3.0*G3; | |
var z3 = z0 - 1.0 + 3.0*G3; | |
// Work out the hashed gradient indices of the four simplex corners | |
var ii = i & 255; | |
var jj = j & 255; | |
var kk = k & 255; | |
var gi0 = this.perm[ii+this.perm[jj+this.perm[kk]]] % 12; | |
var gi1 = this.perm[ii+i1+this.perm[jj+j1+this.perm[kk+k1]]] % 12; | |
var gi2 = this.perm[ii+i2+this.perm[jj+j2+this.perm[kk+k2]]] % 12; | |
var gi3 = this.perm[ii+1+this.perm[jj+1+this.perm[kk+1]]] % 12; | |
// Calculate the contribution from the four corners | |
var t0 = 0.6 - x0*x0 - y0*y0 - z0*z0; | |
if(t0<0) n0 = 0.0; | |
else { | |
t0 *= t0; | |
n0 = t0 * t0 * this.dot(this.grad3[gi0], x0, y0, z0); | |
} | |
var t1 = 0.6 - x1*x1 - y1*y1 - z1*z1; | |
if(t1<0) n1 = 0.0; | |
else { | |
t1 *= t1; | |
n1 = t1 * t1 * this.dot(this.grad3[gi1], x1, y1, z1); | |
} | |
var t2 = 0.6 - x2*x2 - y2*y2 - z2*z2; | |
if(t2<0) n2 = 0.0; | |
else { | |
t2 *= t2; | |
n2 = t2 * t2 * this.dot(this.grad3[gi2], x2, y2, z2); | |
} | |
var t3 = 0.6 - x3*x3 - y3*y3 - z3*z3; | |
if(t3<0) n3 = 0.0; | |
else { | |
t3 *= t3; | |
n3 = t3 * t3 * this.dot(this.grad3[gi3], x3, y3, z3); | |
} | |
// Add contributions from each corner to get the final noise value. | |
// The result is scaled to stay just inside [-1,1] | |
return 32.0*(n0 + n1 + n2 + n3); | |
}; | |
},{}]},{},[]) | |
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uL2hvbWUvYWRtaW4vYnJvd3NlcmlmeS1jZG4vbm9kZV9tb2R1bGVzL2Jyb3dzZXJpZnkvbm9kZV9tb2R1bGVzL2Jyb3dzZXItcGFjay9fcHJlbHVkZS5qcyIsInBlcmxpbi1zaW1wbGV4Il0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBO0FDQUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EiLCJmaWxlIjoiZ2VuZXJhdGVkLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXNDb250ZW50IjpbIihmdW5jdGlvbiBlKHQsbixyKXtmdW5jdGlvbiBzKG8sdSl7aWYoIW5bb10pe2lmKCF0W29dKXt2YXIgYT10eXBlb2YgcmVxdWlyZT09XCJmdW5jdGlvblwiJiZyZXF1aXJlO2lmKCF1JiZhKXJldHVybiBhKG8sITApO2lmKGkpcmV0dXJuIGkobywhMCk7dmFyIGY9bmV3IEVycm9yKFwiQ2Fubm90IGZpbmQgbW9kdWxlICdcIitvK1wiJ1wiKTt0aHJvdyBmLmNvZGU9XCJNT0RVTEVfTk9UX0ZPVU5EXCIsZn12YXIgbD1uW29dPXtleHBvcnRzOnt9fTt0W29dWzBdLmNhbGwobC5leHBvcnRzLGZ1bmN0aW9uKGUpe3ZhciBuPXRbb11bMV1bZV07cmV0dXJuIHMobj9uOmUpfSxsLGwuZXhwb3J0cyxlLHQsbixyKX1yZXR1cm4gbltvXS5leHBvcnRzfXZhciBpPXR5cGVvZiByZXF1aXJlPT1cImZ1bmN0aW9uXCImJnJlcXVpcmU7Zm9yKHZhciBvPTA7bzxyLmxlbmd0aDtvKyspcyhyW29dKTtyZXR1cm4gc30pIiwiLy8gaHR0cHM6Ly9naXN0LmdpdGh1Yi5jb20vYmFua3NlYW4vMzA0NTIyXG4vL1xuLy8gUG9ydGVkIGZyb20gU3RlZmFuIEd1c3RhdnNvbidzIGphdmEgaW1wbGVtZW50YXRpb25cbi8vIGh0dHA6Ly9zdGFmZnd3dy5pdG4ubGl1LnNlL35zdGVndS9zaW1wbGV4bm9pc2Uvc2ltcGxleG5vaXNlLnBkZlxuLy8gUmVhZCBTdGVmYW4ncyBleGNlbGxlbnQgcGFwZXIgZm9yIGRldGFpbHMgb24gaG93IHRoaXMgY29kZSB3b3Jrcy5cbi8vXG4vLyBTZWFuIE1jQ3VsbG91Z2ggYmFua3NlYW5AZ21haWwuY29tXG5cbi8qKlxuICogWW91IGNhbiBwYXNzIGluIGEgcmFuZG9tIG51bWJlciBnZW5lcmF0b3Igb2JqZWN0IGlmIHlvdSBsaWtlLlxuICogSXQgaXMgYXNzdW1lZCB0byBoYXZlIGEgcmFuZG9tKCkgbWV0aG9kLlxuICovXG5tb2R1bGUuZXhwb3J0cyA9IFNpbXBsZXhOb2lzZSA9IGZ1bmN0aW9uKHIpIHtcbiAgaWYgKHIgPT0gdW5kZWZpbmVkKSByID0gTWF0aDtcbiAgdGhpcy5ncmFkMyA9IFtbMSwxLDBdLFstMSwxLDBdLFsxLC0xLDBdLFstMSwtMSwwXSwgXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBbMSwwLDFdLFstMSwwLDFdLFsxLDAsLTFdLFstMSwwLC0xXSwgXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBbMCwxLDFdLFswLC0xLDFdLFswLDEsLTFdLFswLC0xLC0xXV07IFxuICB0aGlzLnAgPSBbXTtcbiAgZm9yICh2YXIgaT0wOyBpPDI1NjsgaSsrKSB7XG4gICAgdGhpcy5wW2ldID0gTWF0aC5mbG9vcihyLnJhbmRvbSgpKjI1Nik7XG4gIH1cbiAgLy8gVG8gcmVtb3ZlIHRoZSBuZWVkIGZvciBpbmRleCB3cmFwcGluZywgZG91YmxlIHRoZSBwZXJtdXRhdGlvbiB0YWJsZSBsZW5ndGggXG4gIHRoaXMucGVybSA9IFtdOyBcbiAgZm9yKHZhciBpPTA7IGk8NTEyOyBpKyspIHtcbiAgICB0aGlzLnBlcm1baV09dGhpcy5wW2kgJiAyNTVdO1xuICB9IFxuXG4gIC8vIEEgbG9va3VwIHRhYmxlIHRvIHRyYXZlcnNlIHRoZSBzaW1wbGV4IGFyb3VuZCBhIGdpdmVuIHBvaW50IGluIDRELiBcbiAgLy8gRGV0YWlscyBjYW4gYmUgZm91bmQgd2hlcmUgdGhpcyB0YWJsZSBpcyB1c2VkLCBpbiB0aGUgNEQgbm9pc2UgbWV0aG9kLiBcbiAgdGhpcy5zaW1wbGV4ID0gWyBcbiAgICBbMCwxLDIsM10sWzAsMSwzLDJdLFswLDAsMCwwXSxbMCwyLDMsMV0sWzAsMCwwLDBdLFswLDAsMCwwXSxbMCwwLDAsMF0sWzEsMiwzLDBdLCBcbiAgICBbMCwyLDEsM10sWzAsMCwwLDBdLFswLDMsMSwyXSxbMCwzLDIsMV0sWzAsMCwwLDBdLFswLDAsMCwwXSxbMCwwLDAsMF0sWzEsMywyLDBdLCBcbiAgICBbMCwwLDAsMF0sWzAsMCwwLDBdLFswLDAsMCwwXSxbMCwwLDAsMF0sWzAsMCwwLDBdLFswLDAsMCwwXSxbMCwwLDAsMF0sWzAsMCwwLDBdLCBcbiAgICBbMSwyLDAsM10sWzAsMCwwLDBdLFsxLDMsMCwyXSxbMCwwLDAsMF0sWzAsMCwwLDBdLFswLDAsMCwwXSxbMiwzLDAsMV0sWzIsMywxLDBdLCBcbiAgICBbMSwwLDIsM10sWzEsMCwzLDJdLFswLDAsMCwwXSxbMCwwLDAsMF0sWzAsMCwwLDBdLFsyLDAsMywxXSxbMCwwLDAsMF0sWzIsMSwzLDBdLCBcbiAgICBbMCwwLDAsMF0sWzAsMCwwLDBdLFswLDAsMCwwXSxbMCwwLDAsMF0sWzAsMCwwLDBdLFswLDAsMCwwXSxbMCwwLDAsMF0sWzAsMCwwLDBdLCBcbiAgICBbMiwwLDEsM10sWzAsMCwwLDBdLFswLDAsMCwwXSxbMCwwLDAsMF0sWzMsMCwxLDJdLFszLDAsMiwxXSxbMCwwLDAsMF0sWzMsMSwyLDBdLCBcbiAgICBbMiwxLDAsM10sWzAsMCwwLDBdLFswLDAsMCwwXSxbMCwwLDAsMF0sWzMsMSwwLDJdLFswLDAsMCwwXSxbMywyLDAsMV0sWzMsMiwxLDBdXTsgXG59O1xuXG5TaW1wbGV4Tm9pc2UucHJvdG90eXBlLmRvdCA9IGZ1bmN0aW9uKGcsIHgsIHkpIHsgXG4gIHJldHVybiBnWzBdKnggKyBnWzFdKnk7XG59O1xuXG5TaW1wbGV4Tm9pc2UucHJvdG90eXBlLm5vaXNlID0gZnVuY3Rpb24oeGluLCB5aW4pIHsgXG4gIHZhciBuMCwgbjEsIG4yOyAvLyBOb2lzZSBjb250cmlidXRpb25zIGZyb20gdGhlIHRocmVlIGNvcm5lcnMgXG4gIC8vIFNrZXcgdGhlIGlucHV0IHNwYWNlIHRvIGRldGVybWluZSB3aGljaCBzaW1wbGV4IGNlbGwgd2UncmUgaW4gXG4gIHZhciBGMiA9IDAuNSooTWF0aC5zcXJ0KDMuMCktMS4wKTsgXG4gIHZhciBzID0gKHhpbit5aW4pKkYyOyAvLyBIYWlyeSBmYWN0b3IgZm9yIDJEIFxuICB2YXIgaSA9IE1hdGguZmxvb3IoeGluK3MpOyBcbiAgdmFyIGogPSBNYXRoLmZsb29yKHlpbitzKTsgXG4gIHZhciBHMiA9ICgzLjAtTWF0aC5zcXJ0KDMuMCkpLzYuMDsgXG4gIHZhciB0ID0gKGkraikqRzI7IFxuICB2YXIgWDAgPSBpLXQ7IC8vIFVuc2tldyB0aGUgY2VsbCBvcmlnaW4gYmFjayB0byAoeCx5KSBzcGFjZSBcbiAgdmFyIFkwID0gai10OyBcbiAgdmFyIHgwID0geGluLVgwOyAvLyBUaGUgeCx5IGRpc3RhbmNlcyBmcm9tIHRoZSBjZWxsIG9yaWdpbiBcbiAgdmFyIHkwID0geWluLVkwOyBcbiAgLy8gRm9yIHRoZSAyRCBjYXNlLCB0aGUgc2ltcGxleCBzaGFwZSBpcyBhbiBlcXVpbGF0ZXJhbCB0cmlhbmdsZS4gXG4gIC8vIERldGVybWluZSB3aGljaCBzaW1wbGV4IHdlIGFyZSBpbi4gXG4gIHZhciBpMSwgajE7IC8vIE9mZnNldHMgZm9yIHNlY29uZCAobWlkZGxlKSBjb3JuZXIgb2Ygc2ltcGxleCBpbiAoaSxqKSBjb29yZHMgXG4gIGlmKHgwPnkwKSB7aTE9MTsgajE9MDt9IC8vIGxvd2VyIHRyaWFuZ2xlLCBYWSBvcmRlcjogKDAsMCktPigxLDApLT4oMSwxKSBcbiAgZWxzZSB7aTE9MDsgajE9MTt9ICAgICAgLy8gdXBwZXIgdHJpYW5nbGUsIFlYIG9yZGVyOiAoMCwwKS0+KDAsMSktPigxLDEpIFxuICAvLyBBIHN0ZXAgb2YgKDEsMCkgaW4gKGksaikgbWVhbnMgYSBzdGVwIG9mICgxLWMsLWMpIGluICh4LHkpLCBhbmQgXG4gIC8vIGEgc3RlcCBvZiAoMCwxKSBpbiAoaSxqKSBtZWFucyBhIHN0ZXAgb2YgKC1jLDEtYykgaW4gKHgseSksIHdoZXJlIFxuICAvLyBjID0gKDMtc3FydCgzKSkvNiBcbiAgdmFyIHgxID0geDAgLSBpMSArIEcyOyAvLyBPZmZzZXRzIGZvciBtaWRkbGUgY29ybmVyIGluICh4LHkpIHVuc2tld2VkIGNvb3JkcyBcbiAgdmFyIHkxID0geTAgLSBqMSArIEcyOyBcbiAgdmFyIHgyID0geDAgLSAxLjAgKyAyLjAgKiBHMjsgLy8gT2Zmc2V0cyBmb3IgbGFzdCBjb3JuZXIgaW4gKHgseSkgdW5za2V3ZWQgY29vcmRzIFxuICB2YXIgeTIgPSB5MCAtIDEuMCArIDIuMCAqIEcyOyBcbiAgLy8gV29yayBvdXQgdGhlIGhhc2hlZCBncmFkaWVudCBpbmRpY2VzIG9mIHRoZSB0aHJlZSBzaW1wbGV4IGNvcm5lcnMgXG4gIHZhciBpaSA9IGkgJiAyNTU7IFxuICB2YXIgamogPSBqICYgMjU1OyBcbiAgdmFyIGdpMCA9IHRoaXMucGVybVtpaSt0aGlzLnBlcm1bampdXSAlIDEyOyBcbiAgdmFyIGdpMSA9IHRoaXMucGVybVtpaStpMSt0aGlzLnBlcm1bamorajFdXSAlIDEyOyBcbiAgdmFyIGdpMiA9IHRoaXMucGVybVtpaSsxK3RoaXMucGVybVtqaisxXV0gJSAxMjsgXG4gIC8vIENhbGN1bGF0ZSB0aGUgY29udHJpYnV0aW9uIGZyb20gdGhlIHRocmVlIGNvcm5lcnMgXG4gIHZhciB0MCA9IDAuNSAtIHgwKngwLXkwKnkwOyBcbiAgaWYodDA8MCkgbjAgPSAwLjA7IFxuICBlbHNlIHsgXG4gICAgdDAgKj0gdDA7IFxuICAgIG4wID0gdDAgKiB0MCAqIHRoaXMuZG90KHRoaXMuZ3JhZDNbZ2kwXSwgeDAsIHkwKTsgIC8vICh4LHkpIG9mIGdyYWQzIHVzZWQgZm9yIDJEIGdyYWRpZW50IFxuICB9IFxuICB2YXIgdDEgPSAwLjUgLSB4MSp4MS15MSp5MTsgXG4gIGlmKHQxPDApIG4xID0gMC4wOyBcbiAgZWxzZSB7IFxuICAgIHQxICo9IHQxOyBcbiAgICBuMSA9IHQxICogdDEgKiB0aGlzLmRvdCh0aGlzLmdyYWQzW2dpMV0sIHgxLCB5MSk7IFxuICB9XG4gIHZhciB0MiA9IDAuNSAtIHgyKngyLXkyKnkyOyBcbiAgaWYodDI8MCkgbjIgPSAwLjA7IFxuICBlbHNlIHsgXG4gICAgdDIgKj0gdDI7IFxuICAgIG4yID0gdDIgKiB0MiAqIHRoaXMuZG90KHRoaXMuZ3JhZDNbZ2kyXSwgeDIsIHkyKTsgXG4gIH0gXG4gIC8vIEFkZCBjb250cmlidXRpb25zIGZyb20gZWFjaCBjb3JuZXIgdG8gZ2V0IHRoZSBmaW5hbCBub2lzZSB2YWx1ZS4gXG4gIC8vIFRoZSByZXN1bHQgaXMgc2NhbGVkIHRvIHJldHVybiB2YWx1ZXMgaW4gdGhlIGludGVydmFsIFstMSwxXS4gXG4gIHJldHVybiA3MC4wICogKG4wICsgbjEgKyBuMik7IFxufTtcblxuLy8gM0Qgc2ltcGxleCBub2lzZSBcblNpbXBsZXhOb2lzZS5wcm90b3R5cGUubm9pc2UzZCA9IGZ1bmN0aW9uKHhpbiwgeWluLCB6aW4pIHsgXG4gIHZhciBuMCwgbjEsIG4yLCBuMzsgLy8gTm9pc2UgY29udHJpYnV0aW9ucyBmcm9tIHRoZSBmb3VyIGNvcm5lcnMgXG4gIC8vIFNrZXcgdGhlIGlucHV0IHNwYWNlIHRvIGRldGVybWluZSB3aGljaCBzaW1wbGV4IGNlbGwgd2UncmUgaW4gXG4gIHZhciBGMyA9IDEuMC8zLjA7IFxuICB2YXIgcyA9ICh4aW4reWluK3ppbikqRjM7IC8vIFZlcnkgbmljZSBhbmQgc2ltcGxlIHNrZXcgZmFjdG9yIGZvciAzRCBcbiAgdmFyIGkgPSBNYXRoLmZsb29yKHhpbitzKTsgXG4gIHZhciBqID0gTWF0aC5mbG9vcih5aW4rcyk7IFxuICB2YXIgayA9IE1hdGguZmxvb3IoemluK3MpOyBcbiAgdmFyIEczID0gMS4wLzYuMDsgLy8gVmVyeSBuaWNlIGFuZCBzaW1wbGUgdW5za2V3IGZhY3RvciwgdG9vIFxuICB2YXIgdCA9IChpK2oraykqRzM7IFxuICB2YXIgWDAgPSBpLXQ7IC8vIFVuc2tldyB0aGUgY2VsbCBvcmlnaW4gYmFjayB0byAoeCx5LHopIHNwYWNlIFxuICB2YXIgWTAgPSBqLXQ7IFxuICB2YXIgWjAgPSBrLXQ7IFxuICB2YXIgeDAgPSB4aW4tWDA7IC8vIFRoZSB4LHkseiBkaXN0YW5jZXMgZnJvbSB0aGUgY2VsbCBvcmlnaW4gXG4gIHZhciB5MCA9IHlpbi1ZMDsgXG4gIHZhciB6MCA9IHppbi1aMDsgXG4gIC8vIEZvciB0aGUgM0QgY2FzZSwgdGhlIHNpbXBsZXggc2hhcGUgaXMgYSBzbGlnaHRseSBpcnJlZ3VsYXIgdGV0cmFoZWRyb24uIFxuICAvLyBEZXRlcm1pbmUgd2hpY2ggc2ltcGxleCB3ZSBhcmUgaW4uIFxuICB2YXIgaTEsIGoxLCBrMTsgLy8gT2Zmc2V0cyBmb3Igc2Vjb25kIGNvcm5lciBvZiBzaW1wbGV4IGluIChpLGosaykgY29vcmRzIFxuICB2YXIgaTIsIGoyLCBrMjsgLy8gT2Zmc2V0cyBmb3IgdGhpcmQgY29ybmVyIG9mIHNpbXBsZXggaW4gKGksaixrKSBjb29yZHMgXG4gIGlmKHgwPj15MCkgeyBcbiAgICBpZih5MD49ejApIFxuICAgICAgeyBpMT0xOyBqMT0wOyBrMT0wOyBpMj0xOyBqMj0xOyBrMj0wOyB9IC8vIFggWSBaIG9yZGVyIFxuICAgICAgZWxzZSBpZih4MD49ejApIHsgaTE9MTsgajE9MDsgazE9MDsgaTI9MTsgajI9MDsgazI9MTsgfSAvLyBYIFogWSBvcmRlciBcbiAgICAgIGVsc2UgeyBpMT0wOyBqMT0wOyBrMT0xOyBpMj0xOyBqMj0wOyBrMj0xOyB9IC8vIFogWCBZIG9yZGVyIFxuICAgIH0gXG4gIGVsc2UgeyAvLyB4MDx5MCBcbiAgICBpZih5MDx6MCkgeyBpMT0wOyBqMT0wOyBrMT0xOyBpMj0wOyBqMj0xOyBrMj0xOyB9IC8vIFogWSBYIG9yZGVyIFxuICAgIGVsc2UgaWYoeDA8ejApIHsgaTE9MDsgajE9MTsgazE9MDsgaTI9MDsgajI9MTsgazI9MTsgfSAvLyBZIFogWCBvcmRlciBcbiAgICBlbHNlIHsgaTE9MDsgajE9MTsgazE9MDsgaTI9MTsgajI9MTsgazI9MDsgfSAvLyBZIFggWiBvcmRlciBcbiAgfSBcbiAgLy8gQSBzdGVwIG9mICgxLDAsMCkgaW4gKGksaixrKSBtZWFucyBhIHN0ZXAgb2YgKDEtYywtYywtYykgaW4gKHgseSx6KSwgXG4gIC8vIGEgc3RlcCBvZiAoMCwxLDApIGluIChpLGosaykgbWVhbnMgYSBzdGVwIG9mICgtYywxLWMsLWMpIGluICh4LHkseiksIGFuZCBcbiAgLy8gYSBzdGVwIG9mICgwLDAsMSkgaW4gKGksaixrKSBtZWFucyBhIHN0ZXAgb2YgKC1jLC1jLDEtYykgaW4gKHgseSx6KSwgd2hlcmUgXG4gIC8vIGMgPSAxLzYuXG4gIHZhciB4MSA9IHgwIC0gaTEgKyBHMzsgLy8gT2Zmc2V0cyBmb3Igc2Vjb25kIGNvcm5lciBpbiAoeCx5LHopIGNvb3JkcyBcbiAgdmFyIHkxID0geTAgLSBqMSArIEczOyBcbiAgdmFyIHoxID0gejAgLSBrMSArIEczOyBcbiAgdmFyIHgyID0geDAgLSBpMiArIDIuMCpHMzsgLy8gT2Zmc2V0cyBmb3IgdGhpcmQgY29ybmVyIGluICh4LHkseikgY29vcmRzIFxuICB2YXIgeTIgPSB5MCAtIGoyICsgMi4wKkczOyBcbiAgdmFyIHoyID0gejAgLSBrMiArIDIuMCpHMzsgXG4gIHZhciB4MyA9IHgwIC0gMS4wICsgMy4wKkczOyAvLyBPZmZzZXRzIGZvciBsYXN0IGNvcm5lciBpbiAoeCx5LHopIGNvb3JkcyBcbiAgdmFyIHkzID0geTAgLSAxLjAgKyAzLjAqRzM7IFxuICB2YXIgejMgPSB6MCAtIDEuMCArIDMuMCpHMzsgXG4gIC8vIFdvcmsgb3V0IHRoZSBoYXNoZWQgZ3JhZGllbnQgaW5kaWNlcyBvZiB0aGUgZm91ciBzaW1wbGV4IGNvcm5lcnMgXG4gIHZhciBpaSA9IGkgJiAyNTU7IFxuICB2YXIgamogPSBqICYgMjU1OyBcbiAgdmFyIGtrID0gayAmIDI1NTsgXG4gIHZhciBnaTAgPSB0aGlzLnBlcm1baWkrdGhpcy5wZXJtW2pqK3RoaXMucGVybVtra11dXSAlIDEyOyBcbiAgdmFyIGdpMSA9IHRoaXMucGVybVtpaStpMSt0aGlzLnBlcm1bamorajErdGhpcy5wZXJtW2trK2sxXV1dICUgMTI7IFxuICB2YXIgZ2kyID0gdGhpcy5wZXJtW2lpK2kyK3RoaXMucGVybVtqaitqMit0aGlzLnBlcm1ba2srazJdXV0gJSAxMjsgXG4gIHZhciBnaTMgPSB0aGlzLnBlcm1baWkrMSt0aGlzLnBlcm1bamorMSt0aGlzLnBlcm1ba2srMV1dXSAlIDEyOyBcbiAgLy8gQ2FsY3VsYXRlIHRoZSBjb250cmlidXRpb24gZnJvbSB0aGUgZm91ciBjb3JuZXJzIFxuICB2YXIgdDAgPSAwLjYgLSB4MCp4MCAtIHkwKnkwIC0gejAqejA7IFxuICBpZih0MDwwKSBuMCA9IDAuMDsgXG4gIGVsc2UgeyBcbiAgICB0MCAqPSB0MDsgXG4gICAgbjAgPSB0MCAqIHQwICogdGhpcy5kb3QodGhpcy5ncmFkM1tnaTBdLCB4MCwgeTAsIHowKTsgXG4gIH1cbiAgdmFyIHQxID0gMC42IC0geDEqeDEgLSB5MSp5MSAtIHoxKnoxOyBcbiAgaWYodDE8MCkgbjEgPSAwLjA7IFxuICBlbHNlIHsgXG4gICAgdDEgKj0gdDE7IFxuICAgIG4xID0gdDEgKiB0MSAqIHRoaXMuZG90KHRoaXMuZ3JhZDNbZ2kxXSwgeDEsIHkxLCB6MSk7IFxuICB9IFxuICB2YXIgdDIgPSAwLjYgLSB4Mip4MiAtIHkyKnkyIC0gejIqejI7IFxuICBpZih0MjwwKSBuMiA9IDAuMDsgXG4gIGVsc2UgeyBcbiAgICB0MiAqPSB0MjsgXG4gICAgbjIgPSB0MiAqIHQyICogdGhpcy5kb3QodGhpcy5ncmFkM1tnaTJdLCB4MiwgeTIsIHoyKTsgXG4gIH0gXG4gIHZhciB0MyA9IDAuNiAtIHgzKngzIC0geTMqeTMgLSB6Myp6MzsgXG4gIGlmKHQzPDApIG4zID0gMC4wOyBcbiAgZWxzZSB7IFxuICAgIHQzICo9IHQzOyBcbiAgICBuMyA9IHQzICogdDMgKiB0aGlzLmRvdCh0aGlzLmdyYWQzW2dpM10sIHgzLCB5MywgejMpOyBcbiAgfSBcbiAgLy8gQWRkIGNvbnRyaWJ1dGlvbnMgZnJvbSBlYWNoIGNvcm5lciB0byBnZXQgdGhlIGZpbmFsIG5vaXNlIHZhbHVlLiBcbiAgLy8gVGhlIHJlc3VsdCBpcyBzY2FsZWQgdG8gc3RheSBqdXN0IGluc2lkZSBbLTEsMV0gXG4gIHJldHVybiAzMi4wKihuMCArIG4xICsgbjIgKyBuMyk7IFxufTsiXX0= | |
require=(function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({"delaunator":[function(require,module,exports){ | |
'use strict'; | |
module.exports = Delaunator; | |
function Delaunator(points, getX, getY) { | |
if (!getX) getX = defaultGetX; | |
if (!getY) getY = defaultGetY; | |
var minX = Infinity; | |
var minY = Infinity; | |
var maxX = -Infinity; | |
var maxY = -Infinity; | |
var coords = this.coords = []; | |
var ids = this.ids = new Uint32Array(points.length); | |
for (var i = 0; i < points.length; i++) { | |
var p = points[i]; | |
var x = getX(p); | |
var y = getY(p); | |
ids[i] = i; | |
coords[2 * i] = x; | |
coords[2 * i + 1] = y; | |
if (x < minX) minX = x; | |
if (y < minY) minY = y; | |
if (x > maxX) maxX = x; | |
if (y > maxY) maxY = y; | |
} | |
var cx = (minX + maxX) / 2; | |
var cy = (minY + maxY) / 2; | |
var minDist = Infinity; | |
var i0, i1, i2; | |
// pick a seed point close to the centroid | |
for (i = 0; i < points.length; i++) { | |
var d = dist(cx, cy, coords[2 * i], coords[2 * i + 1]); | |
if (d < minDist) { | |
i0 = i; | |
minDist = d; | |
} | |
} | |
minDist = Infinity; | |
// find the point closest to the seed | |
for (i = 0; i < points.length; i++) { | |
if (i === i0) continue; | |
d = dist(coords[2 * i0], coords[2 * i0 + 1], coords[2 * i], coords[2 * i + 1]); | |
if (d < minDist && d > 0) { | |
i1 = i; | |
minDist = d; | |
} | |
} | |
var minRadius = Infinity; | |
// find the third point which forms the smallest circumcircle with the first two | |
for (i = 0; i < points.length; i++) { | |
if (i === i0 || i === i1) continue; | |
var r = circumradius( | |
coords[2 * i0], coords[2 * i0 + 1], | |
coords[2 * i1], coords[2 * i1 + 1], | |
coords[2 * i], coords[2 * i + 1]); | |
if (r < minRadius) { | |
i2 = i; | |
minRadius = r; | |
} | |
} | |
if (minRadius === Infinity) { | |
throw new Error('No Delaunay triangulation exists for this input.'); | |
} | |
// swap the order of the seed points for counter-clockwise orientation | |
if (area(coords[2 * i0], coords[2 * i0 + 1], | |
coords[2 * i1], coords[2 * i1 + 1], | |
coords[2 * i2], coords[2 * i2 + 1]) < 0) { | |
var tmp = i1; | |
i1 = i2; | |
i2 = tmp; | |
} | |
var i0x = coords[2 * i0]; | |
var i0y = coords[2 * i0 + 1]; | |
var i1x = coords[2 * i1]; | |
var i1y = coords[2 * i1 + 1]; | |
var i2x = coords[2 * i2]; | |
var i2y = coords[2 * i2 + 1]; | |
var center = circumcenter(i0x, i0y, i1x, i1y, i2x, i2y); | |
this._cx = center.x; | |
this._cy = center.y; | |
// sort the points by distance from the seed triangle circumcenter | |
quicksort(ids, coords, 0, ids.length - 1, center.x, center.y); | |
// initialize a hash table for storing edges of the advancing convex hull | |
this._hashSize = Math.ceil(Math.sqrt(points.length)); | |
this._hash = []; | |
for (i = 0; i < this._hashSize; i++) this._hash[i] = null; | |
// initialize a circular doubly-linked list that will hold an advancing convex hull | |
var e = this.hull = insertNode(coords, i0); | |
this._hashEdge(e); | |
e.t = 0; | |
e = insertNode(coords, i1, e); | |
this._hashEdge(e); | |
e.t = 1; | |
e = insertNode(coords, i2, e); | |
this._hashEdge(e); | |
e.t = 2; | |
var maxTriangles = 2 * points.length - 5; | |
var triangles = this.triangles = new Uint32Array(maxTriangles * 3); | |
triangles[0] = i0; | |
triangles[1] = i1; | |
triangles[2] = i2; | |
this.trianglesLen = 3; | |
var adjacent = this.adjacent = new Int32Array(maxTriangles * 3); | |
adjacent[0] = -1; | |
adjacent[1] = -1; | |
adjacent[2] = -1; | |
var xp, yp; | |
for (var k = 0; k < ids.length; k++) { | |
i = ids[k]; | |
x = coords[2 * i]; | |
y = coords[2 * i + 1]; | |
// skip duplicate points | |
if (x === xp && y === yp) continue; | |
xp = x; | |
yp = y; | |
// skip seed triangle points | |
if ((x === i0x && y === i0y) || | |
(x === i1x && y === i1y) || | |
(x === i2x && y === i2y)) continue; | |
// find a visible edge on the convex hull using edge hash | |
var startKey = this._hashKey(x, y); | |
var key = startKey; | |
var start; | |
do { | |
start = this._hash[key]; | |
key = (key + 1) % this._hashSize; | |
} while ((!start || start.removed) && key !== startKey); | |
e = start; | |
while (area(x, y, e.x, e.y, e.next.x, e.next.y) >= 0) { | |
e = e.next; | |
if (e === start) { | |
throw new Error('Something is wrong with the input points.'); | |
} | |
} | |
var walkBack = e === start; | |
// add the first triangle from the point | |
var t = this._addTriangle(i, e); | |
adjacent[t] = -1; | |
adjacent[t + 1] = -1; | |
this._link(t + 2, e.t); | |
e.t = t; // keep track of boundary triangles on the hull | |
e = insertNode(coords, i, e); | |
// recursively flip triangles from the point until they satisfy the Delaunay condition | |
e.t = this._legalize(t + 2); | |
// walk forward through the hull, adding more triangles and flipping recursively | |
var q = e.next; | |
while (area(x, y, q.x, q.y, q.next.x, q.next.y) < 0) { | |
t = this._addTriangle(i, q); | |
this._link(t, q.prev.t); | |
adjacent[t + 1] = -1; | |
this._link(t + 2, q.t); | |
q.prev.t = this._legalize(t + 2); | |
this.hull = removeNode(q); | |
q = q.next; | |
} | |
if (walkBack) { | |
// walk backward from the other side, adding more triangles and flipping | |
q = e.prev; | |
while (area(x, y, q.prev.x, q.prev.y, q.x, q.y) < 0) { | |
t = this._addTriangle(i, q.prev); | |
adjacent[t] = -1; | |
this._link(t + 1, q.t); | |
this._link(t + 2, q.prev.t); | |
this._legalize(t + 2); | |
q.prev.t = t; | |
this.hull = removeNode(q); | |
q = q.prev; | |
} | |
} | |
// save the two new edges in the hash table | |
this._hashEdge(e); | |
this._hashEdge(e.prev); | |
} | |
// trim typed triangle mesh arrays | |
this.triangles = triangles.subarray(0, this.trianglesLen); | |
this.adjacent = adjacent.subarray(0, this.trianglesLen); | |
} | |
Delaunator.prototype = { | |
_hashEdge: function (e) { | |
this._hash[this._hashKey(e.x, e.y)] = e; | |
}, | |
_hashKey: function (x, y) { | |
var dx = x - this._cx; | |
var dy = y - this._cy; | |
// use pseudo-angle: a measure that monotonically increases | |
// with real angle, but doesn't require expensive trigonometry | |
var p = 1 - dx / (Math.abs(dx) + Math.abs(dy)); | |
return Math.floor((2 + (dy < 0 ? -p : p)) * (this._hashSize / 4)); | |
}, | |
_legalize: function (a) { | |
var triangles = this.triangles; | |
var coords = this.coords; | |
var adjacent = this.adjacent; | |
var b = adjacent[a]; | |
var a0 = a - a % 3; | |
var b0 = b - b % 3; | |
var al = a0 + (a + 1) % 3; | |
var ar = a0 + (a + 2) % 3; | |
var br = b0 + (b + 1) % 3; | |
var bl = b0 + (b + 2) % 3; | |
var p0 = triangles[ar]; | |
var pr = triangles[a]; | |
var pl = triangles[al]; | |
var p1 = triangles[bl]; | |
var illegal = inCircle( | |
coords[2 * p0], coords[2 * p0 + 1], | |
coords[2 * pr], coords[2 * pr + 1], | |
coords[2 * pl], coords[2 * pl + 1], | |
coords[2 * p1], coords[2 * p1 + 1]); | |
if (illegal) { | |
triangles[a] = p1; | |
triangles[b] = p0; | |
this._link(a, adjacent[bl]); | |
this._link(b, adjacent[ar]); | |
this._link(ar, bl); | |
this._legalize(a); | |
return this._legalize(br); | |
} | |
return ar; | |
}, | |
_link: function (a, b) { | |
this.adjacent[a] = b; | |
if (b !== -1) this.adjacent[b] = a; | |
}, | |
_addTriangle(i, e) { | |
var t = this.trianglesLen; | |
this.triangles[t] = e.i; | |
this.triangles[t + 1] = i; | |
this.triangles[t + 2] = e.next.i; | |
this.trianglesLen += 3; | |
return t; | |
} | |
}; | |
function dist(ax, ay, bx, by) { | |
var dx = ax - bx; | |
var dy = ay - by; | |
return dx * dx + dy * dy; | |
} | |
function area(px, py, qx, qy, rx, ry) { | |
return (qy - py) * (rx - qx) - (qx - px) * (ry - qy); | |
} | |
function inCircle(ax, ay, bx, by, cx, cy, px, py) { | |
ax -= px; | |
ay -= py; | |
bx -= px; | |
by -= py; | |
cx -= px; | |
cy -= py; | |
var ap = ax * ax + ay * ay; | |
var bp = bx * bx + by * by; | |
var cp = cx * cx + cy * cy; | |
var det = ax * (by * cp - bp * cy) - | |
ay * (bx * cp - bp * cx) + | |
ap * (bx * cy - by * cx); | |
return det < 0; | |
} | |
function circumradius(ax, ay, bx, by, cx, cy) { | |
bx -= ax; | |
by -= ay; | |
cx -= ax; | |
cy -= ay; | |
var bl = bx * bx + by * by; | |
var cl = cx * cx + cy * cy; | |
if (bl === 0 || cl === 0) return Infinity; | |
var d = bx * cy - by * cx; | |
if (d === 0) return Infinity; | |
var x = (cy * bl - by * cl) * 0.5 / d; | |
var y = (bx * cl - cx * bl) * 0.5 / d; | |
return x * x + y * y; | |
} | |
function circumcenter(ax, ay, bx, by, cx, cy) { | |
bx -= ax; | |
by -= ay; | |
cx -= ax; | |
cy -= ay; | |
var bl = bx * bx + by * by; | |
var cl = cx * cx + cy * cy; | |
var d = bx * cy - by * cx; | |
var x = (cy * bl - by * cl) * 0.5 / d; | |
var y = (bx * cl - cx * bl) * 0.5 / d; | |
return { | |
x: ax + x, | |
y: ay + y | |
}; | |
} | |
// create a new node in a doubly linked list | |
function insertNode(coords, i, prev) { | |
var node = { | |
i: i, | |
x: coords[2 * i], | |
y: coords[2 * i + 1], | |
t: 0, | |
prev: null, | |
next: null, | |
removed: false | |
}; | |
if (!prev) { | |
node.prev = node; | |
node.next = node; | |
} else { | |
node.next = prev.next; | |
node.prev = prev; | |
prev.next.prev = node; | |
prev.next = node; | |
} | |
return node; | |
} | |
function removeNode(node) { | |
node.prev.next = node.next; | |
node.next.prev = node.prev; | |
node.removed = true; | |
return node.prev; | |
} | |
function quicksort(ids, coords, left, right, cx, cy) { | |
var i, j, temp; | |
if (right - left <= 20) { | |
for (i = left + 1; i <= right; i++) { | |
temp = ids[i]; | |
j = i - 1; | |
while (j >= left && compare(coords, ids[j], temp, cx, cy) > 0) ids[j + 1] = ids[j--]; | |
ids[j + 1] = temp; | |
} | |
} else { | |
var median = (left + right) >> 1; | |
i = left + 1; | |
j = right; | |
swap(ids, median, i); | |
if (compare(coords, ids[left], ids[right], cx, cy) > 0) swap(ids, left, right); | |
if (compare(coords, ids[i], ids[right], cx, cy) > 0) swap(ids, i, right); | |
if (compare(coords, ids[left], ids[i], cx, cy) > 0) swap(ids, left, i); | |
temp = ids[i]; | |
while (true) { | |
do i++; while (compare(coords, ids[i], temp, cx, cy) < 0); | |
do j--; while (compare(coords, ids[j], temp, cx, cy) > 0); | |
if (j < i) break; | |
swap(ids, i, j); | |
} | |
ids[left + 1] = ids[j]; | |
ids[j] = temp; | |
if (right - i + 1 >= j - left) { | |
quicksort(ids, coords, i, right, cx, cy); | |
quicksort(ids, coords, left, j - 1, cx, cy); | |
} else { | |
quicksort(ids, coords, left, j - 1, cx, cy); | |
quicksort(ids, coords, i, right, cx, cy); | |
} | |
} | |
} | |
function compare(coords, i, j, cx, cy) { | |
var d1 = dist(coords[2 * i], coords[2 * i + 1], cx, cy); | |
var d2 = dist(coords[2 * j], coords[2 * j + 1], cx, cy); | |
return (d1 - d2) || (coords[2 * i] - coords[2 * j]) || (coords[2 * i + 1] - coords[2 * j + 1]); | |
} | |
function swap(arr, i, j) { | |
var tmp = arr[i]; | |
arr[i] = arr[j]; | |
arr[j] = tmp; | |
} | |
function defaultGetX(p) { | |
return p[0]; | |
} | |
function defaultGetY(p) { | |
return p[1]; | |
} | |
},{}]},{},[]) | |
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uL2hvbWUvYWRtaW4vYnJvd3NlcmlmeS1jZG4vbm9kZV9tb2R1bGVzL2Jyb3dzZXJpZnkvbm9kZV9tb2R1bGVzL2Jyb3dzZXItcGFjay9fcHJlbHVkZS5qcyIsImRlbGF1bmF0b3IiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUE7QUNBQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EiLCJmaWxlIjoiZ2VuZXJhdGVkLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXNDb250ZW50IjpbIihmdW5jdGlvbiBlKHQsbixyKXtmdW5jdGlvbiBzKG8sdSl7aWYoIW5bb10pe2lmKCF0W29dKXt2YXIgYT10eXBlb2YgcmVxdWlyZT09XCJmdW5jdGlvblwiJiZyZXF1aXJlO2lmKCF1JiZhKXJldHVybiBhKG8sITApO2lmKGkpcmV0dXJuIGkobywhMCk7dmFyIGY9bmV3IEVycm9yKFwiQ2Fubm90IGZpbmQgbW9kdWxlICdcIitvK1wiJ1wiKTt0aHJvdyBmLmNvZGU9XCJNT0RVTEVfTk9UX0ZPVU5EXCIsZn12YXIgbD1uW29dPXtleHBvcnRzOnt9fTt0W29dWzBdLmNhbGwobC5leHBvcnRzLGZ1bmN0aW9uKGUpe3ZhciBuPXRbb11bMV1bZV07cmV0dXJuIHMobj9uOmUpfSxsLGwuZXhwb3J0cyxlLHQsbixyKX1yZXR1cm4gbltvXS5leHBvcnRzfXZhciBpPXR5cGVvZiByZXF1aXJlPT1cImZ1bmN0aW9uXCImJnJlcXVpcmU7Zm9yKHZhciBvPTA7bzxyLmxlbmd0aDtvKyspcyhyW29dKTtyZXR1cm4gc30pIiwiJ3VzZSBzdHJpY3QnO1xuXG5tb2R1bGUuZXhwb3J0cyA9IERlbGF1bmF0b3I7XG5cbmZ1bmN0aW9uIERlbGF1bmF0b3IocG9pbnRzLCBnZXRYLCBnZXRZKSB7XG5cbiAgICBpZiAoIWdldFgpIGdldFggPSBkZWZhdWx0R2V0WDtcbiAgICBpZiAoIWdldFkpIGdldFkgPSBkZWZhdWx0R2V0WTtcblxuICAgIHZhciBtaW5YID0gSW5maW5pdHk7XG4gICAgdmFyIG1pblkgPSBJbmZpbml0eTtcbiAgICB2YXIgbWF4WCA9IC1JbmZpbml0eTtcbiAgICB2YXIgbWF4WSA9IC1JbmZpbml0eTtcblxuICAgIHZhciBjb29yZHMgPSB0aGlzLmNvb3JkcyA9IFtdO1xuICAgIHZhciBpZHMgPSB0aGlzLmlkcyA9IG5ldyBVaW50MzJBcnJheShwb2ludHMubGVuZ3RoKTtcblxuICAgIGZvciAodmFyIGkgPSAwOyBpIDwgcG9pbnRzLmxlbmd0aDsgaSsrKSB7XG4gICAgICAgIHZhciBwID0gcG9pbnRzW2ldO1xuICAgICAgICB2YXIgeCA9IGdldFgocCk7XG4gICAgICAgIHZhciB5ID0gZ2V0WShwKTtcbiAgICAgICAgaWRzW2ldID0gaTtcbiAgICAgICAgY29vcmRzWzIgKiBpXSA9IHg7XG4gICAgICAgIGNvb3Jkc1syICogaSArIDFdID0geTtcbiAgICAgICAgaWYgKHggPCBtaW5YKSBtaW5YID0geDtcbiAgICAgICAgaWYgKHkgPCBtaW5ZKSBtaW5ZID0geTtcbiAgICAgICAgaWYgKHggPiBtYXhYKSBtYXhYID0geDtcbiAgICAgICAgaWYgKHkgPiBtYXhZKSBtYXhZID0geTtcbiAgICB9XG5cbiAgICB2YXIgY3ggPSAobWluWCArIG1heFgpIC8gMjtcbiAgICB2YXIgY3kgPSAobWluWSArIG1heFkpIC8gMjtcblxuICAgIHZhciBtaW5EaXN0ID0gSW5maW5pdHk7XG4gICAgdmFyIGkwLCBpMSwgaTI7XG5cbiAgICAvLyBwaWNrIGEgc2VlZCBwb2ludCBjbG9zZSB0byB0aGUgY2VudHJvaWRcbiAgICBmb3IgKGkgPSAwOyBpIDwgcG9pbnRzLmxlbmd0aDsgaSsrKSB7XG4gICAgICAgIHZhciBkID0gZGlzdChjeCwgY3ksIGNvb3Jkc1syICogaV0sIGNvb3Jkc1syICogaSArIDFdKTtcbiAgICAgICAgaWYgKGQgPCBtaW5EaXN0KSB7XG4gICAgICAgICAgICBpMCA9IGk7XG4gICAgICAgICAgICBtaW5EaXN0ID0gZDtcbiAgICAgICAgfVxuICAgIH1cblxuICAgIG1pbkRpc3QgPSBJbmZpbml0eTtcblxuICAgIC8vIGZpbmQgdGhlIHBvaW50IGNsb3Nlc3QgdG8gdGhlIHNlZWRcbiAgICBmb3IgKGkgPSAwOyBpIDwgcG9pbnRzLmxlbmd0aDsgaSsrKSB7XG4gICAgICAgIGlmIChpID09PSBpMCkgY29udGludWU7XG4gICAgICAgIGQgPSBkaXN0KGNvb3Jkc1syICogaTBdLCBjb29yZHNbMiAqIGkwICsgMV0sIGNvb3Jkc1syICogaV0sIGNvb3Jkc1syICogaSArIDFdKTtcbiAgICAgICAgaWYgKGQgPCBtaW5EaXN0ICYmIGQgPiAwKSB7XG4gICAgICAgICAgICBpMSA9IGk7XG4gICAgICAgICAgICBtaW5EaXN0ID0gZDtcbiAgICAgICAgfVxuICAgIH1cblxuICAgIHZhciBtaW5SYWRpdXMgPSBJbmZpbml0eTtcblxuICAgIC8vIGZpbmQgdGhlIHRoaXJkIHBvaW50IHdoaWNoIGZvcm1zIHRoZSBzbWFsbGVzdCBjaXJjdW1jaXJjbGUgd2l0aCB0aGUgZmlyc3QgdHdvXG4gICAgZm9yIChpID0gMDsgaSA8IHBvaW50cy5sZW5ndGg7IGkrKykge1xuICAgICAgICBpZiAoaSA9PT0gaTAgfHwgaSA9PT0gaTEpIGNvbnRpbnVlO1xuXG4gICAgICAgIHZhciByID0gY2lyY3VtcmFkaXVzKFxuICAgICAgICAgICAgY29vcmRzWzIgKiBpMF0sIGNvb3Jkc1syICogaTAgKyAxXSxcbiAgICAgICAgICAgIGNvb3Jkc1syICogaTFdLCBjb29yZHNbMiAqIGkxICsgMV0sXG4gICAgICAgICAgICBjb29yZHNbMiAqIGldLCBjb29yZHNbMiAqIGkgKyAxXSk7XG5cbiAgICAgICAgaWYgKHIgPCBtaW5SYWRpdXMpIHtcbiAgICAgICAgICAgIGkyID0gaTtcbiAgICAgICAgICAgIG1pblJhZGl1cyA9IHI7XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICBpZiAobWluUmFkaXVzID09PSBJbmZpbml0eSkge1xuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoJ05vIERlbGF1bmF5IHRyaWFuZ3VsYXRpb24gZXhpc3RzIGZvciB0aGlzIGlucHV0LicpO1xuICAgIH1cblxuICAgIC8vIHN3YXAgdGhlIG9yZGVyIG9mIHRoZSBzZWVkIHBvaW50cyBmb3IgY291bnRlci1jbG9ja3dpc2Ugb3JpZW50YXRpb25cbiAgICBpZiAoYXJlYShjb29yZHNbMiAqIGkwXSwgY29vcmRzWzIgKiBpMCArIDFdLFxuICAgICAgICAgICAgIGNvb3Jkc1syICogaTFdLCBjb29yZHNbMiAqIGkxICsgMV0sXG4gICAgICAgICAgICAgY29vcmRzWzIgKiBpMl0sIGNvb3Jkc1syICogaTIgKyAxXSkgPCAwKSB7XG5cbiAgICAgICAgdmFyIHRtcCA9IGkxO1xuICAgICAgICBpMSA9IGkyO1xuICAgICAgICBpMiA9IHRtcDtcbiAgICB9XG5cbiAgICB2YXIgaTB4ID0gY29vcmRzWzIgKiBpMF07XG4gICAgdmFyIGkweSA9IGNvb3Jkc1syICogaTAgKyAxXTtcbiAgICB2YXIgaTF4ID0gY29vcmRzWzIgKiBpMV07XG4gICAgdmFyIGkxeSA9IGNvb3Jkc1syICogaTEgKyAxXTtcbiAgICB2YXIgaTJ4ID0gY29vcmRzWzIgKiBpMl07XG4gICAgdmFyIGkyeSA9IGNvb3Jkc1syICogaTIgKyAxXTtcblxuICAgIHZhciBjZW50ZXIgPSBjaXJjdW1jZW50ZXIoaTB4LCBpMHksIGkxeCwgaTF5LCBpMngsIGkyeSk7XG4gICAgdGhpcy5fY3ggPSBjZW50ZXIueDtcbiAgICB0aGlzLl9jeSA9IGNlbnRlci55O1xuXG4gICAgLy8gc29ydCB0aGUgcG9pbnRzIGJ5IGRpc3RhbmNlIGZyb20gdGhlIHNlZWQgdHJpYW5nbGUgY2lyY3VtY2VudGVyXG4gICAgcXVpY2tzb3J0KGlkcywgY29vcmRzLCAwLCBpZHMubGVuZ3RoIC0gMSwgY2VudGVyLngsIGNlbnRlci55KTtcblxuICAgIC8vIGluaXRpYWxpemUgYSBoYXNoIHRhYmxlIGZvciBzdG9yaW5nIGVkZ2VzIG9mIHRoZSBhZHZhbmNpbmcgY29udmV4IGh1bGxcbiAgICB0aGlzLl9oYXNoU2l6ZSA9IE1hdGguY2VpbChNYXRoLnNxcnQocG9pbnRzLmxlbmd0aCkpO1xuICAgIHRoaXMuX2hhc2ggPSBbXTtcbiAgICBmb3IgKGkgPSAwOyBpIDwgdGhpcy5faGFzaFNpemU7IGkrKykgdGhpcy5faGFzaFtpXSA9IG51bGw7XG5cbiAgICAvLyBpbml0aWFsaXplIGEgY2lyY3VsYXIgZG91Ymx5LWxpbmtlZCBsaXN0IHRoYXQgd2lsbCBob2xkIGFuIGFkdmFuY2luZyBjb252ZXggaHVsbFxuICAgIHZhciBlID0gdGhpcy5odWxsID0gaW5zZXJ0Tm9kZShjb29yZHMsIGkwKTtcbiAgICB0aGlzLl9oYXNoRWRnZShlKTtcbiAgICBlLnQgPSAwO1xuICAgIGUgPSBpbnNlcnROb2RlKGNvb3JkcywgaTEsIGUpO1xuICAgIHRoaXMuX2hhc2hFZGdlKGUpO1xuICAgIGUudCA9IDE7XG4gICAgZSA9IGluc2VydE5vZGUoY29vcmRzLCBpMiwgZSk7XG4gICAgdGhpcy5faGFzaEVkZ2UoZSk7XG4gICAgZS50ID0gMjtcblxuICAgIHZhciBtYXhUcmlhbmdsZXMgPSAyICogcG9pbnRzLmxlbmd0aCAtIDU7XG4gICAgdmFyIHRyaWFuZ2xlcyA9IHRoaXMudHJpYW5nbGVzID0gbmV3IFVpbnQzMkFycmF5KG1heFRyaWFuZ2xlcyAqIDMpO1xuICAgIHRyaWFuZ2xlc1swXSA9IGkwO1xuICAgIHRyaWFuZ2xlc1sxXSA9IGkxO1xuICAgIHRyaWFuZ2xlc1syXSA9IGkyO1xuICAgIHRoaXMudHJpYW5nbGVzTGVuID0gMztcblxuICAgIHZhciBhZGphY2VudCA9IHRoaXMuYWRqYWNlbnQgPSBuZXcgSW50MzJBcnJheShtYXhUcmlhbmdsZXMgKiAzKTtcbiAgICBhZGphY2VudFswXSA9IC0xO1xuICAgIGFkamFjZW50WzFdID0gLTE7XG4gICAgYWRqYWNlbnRbMl0gPSAtMTtcblxuICAgIHZhciB4cCwgeXA7XG4gICAgZm9yICh2YXIgayA9IDA7IGsgPCBpZHMubGVuZ3RoOyBrKyspIHtcbiAgICAgICAgaSA9IGlkc1trXTtcbiAgICAgICAgeCA9IGNvb3Jkc1syICogaV07XG4gICAgICAgIHkgPSBjb29yZHNbMiAqIGkgKyAxXTtcblxuICAgICAgICAvLyBza2lwIGR1cGxpY2F0ZSBwb2ludHNcbiAgICAgICAgaWYgKHggPT09IHhwICYmIHkgPT09IHlwKSBjb250aW51ZTtcbiAgICAgICAgeHAgPSB4O1xuICAgICAgICB5cCA9IHk7XG5cbiAgICAgICAgLy8gc2tpcCBzZWVkIHRyaWFuZ2xlIHBvaW50c1xuICAgICAgICBpZiAoKHggPT09IGkweCAmJiB5ID09PSBpMHkpIHx8XG4gICAgICAgICAgICAoeCA9PT0gaTF4ICYmIHkgPT09IGkxeSkgfHxcbiAgICAgICAgICAgICh4ID09PSBpMnggJiYgeSA9PT0gaTJ5KSkgY29udGludWU7XG5cbiAgICAgICAgLy8gZmluZCBhIHZpc2libGUgZWRnZSBvbiB0aGUgY29udmV4IGh1bGwgdXNpbmcgZWRnZSBoYXNoXG4gICAgICAgIHZhciBzdGFydEtleSA9IHRoaXMuX2hhc2hLZXkoeCwgeSk7XG4gICAgICAgIHZhciBrZXkgPSBzdGFydEtleTtcbiAgICAgICAgdmFyIHN0YXJ0O1xuICAgICAgICBkbyB7XG4gICAgICAgICAgICBzdGFydCA9IHRoaXMuX2hhc2hba2V5XTtcbiAgICAgICAgICAgIGtleSA9IChrZXkgKyAxKSAlIHRoaXMuX2hhc2hTaXplO1xuICAgICAgICB9IHdoaWxlICgoIXN0YXJ0IHx8IHN0YXJ0LnJlbW92ZWQpICYmIGtleSAhPT0gc3RhcnRLZXkpO1xuXG4gICAgICAgIGUgPSBzdGFydDtcbiAgICAgICAgd2hpbGUgKGFyZWEoeCwgeSwgZS54LCBlLnksIGUubmV4dC54LCBlLm5leHQueSkgPj0gMCkge1xuICAgICAgICAgICAgZSA9IGUubmV4dDtcbiAgICAgICAgICAgIGlmIChlID09PSBzdGFydCkge1xuICAgICAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcignU29tZXRoaW5nIGlzIHdyb25nIHdpdGggdGhlIGlucHV0IHBvaW50cy4nKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuXG4gICAgICAgIHZhciB3YWxrQmFjayA9IGUgPT09IHN0YXJ0O1xuXG4gICAgICAgIC8vIGFkZCB0aGUgZmlyc3QgdHJpYW5nbGUgZnJvbSB0aGUgcG9pbnRcbiAgICAgICAgdmFyIHQgPSB0aGlzLl9hZGRUcmlhbmdsZShpLCBlKTtcbiAgICAgICAgYWRqYWNlbnRbdF0gPSAtMTtcbiAgICAgICAgYWRqYWNlbnRbdCArIDFdID0gLTE7XG4gICAgICAgIHRoaXMuX2xpbmsodCArIDIsIGUudCk7XG5cbiAgICAgICAgZS50ID0gdDsgLy8ga2VlcCB0cmFjayBvZiBib3VuZGFyeSB0cmlhbmdsZXMgb24gdGhlIGh1bGxcbiAgICAgICAgZSA9IGluc2VydE5vZGUoY29vcmRzLCBpLCBlKTtcblxuICAgICAgICAvLyByZWN1cnNpdmVseSBmbGlwIHRyaWFuZ2xlcyBmcm9tIHRoZSBwb2ludCB1bnRpbCB0aGV5IHNhdGlzZnkgdGhlIERlbGF1bmF5IGNvbmRpdGlvblxuICAgICAgICBlLnQgPSB0aGlzLl9sZWdhbGl6ZSh0ICsgMik7XG5cbiAgICAgICAgLy8gd2FsayBmb3J3YXJkIHRocm91Z2ggdGhlIGh1bGwsIGFkZGluZyBtb3JlIHRyaWFuZ2xlcyBhbmQgZmxpcHBpbmcgcmVjdXJzaXZlbHlcbiAgICAgICAgdmFyIHEgPSBlLm5leHQ7XG4gICAgICAgIHdoaWxlIChhcmVhKHgsIHksIHEueCwgcS55LCBxLm5leHQueCwgcS5uZXh0LnkpIDwgMCkge1xuXG4gICAgICAgICAgICB0ID0gdGhpcy5fYWRkVHJpYW5nbGUoaSwgcSk7XG4gICAgICAgICAgICB0aGlzLl9saW5rKHQsIHEucHJldi50KTtcbiAgICAgICAgICAgIGFkamFjZW50W3QgKyAxXSA9IC0xO1xuICAgICAgICAgICAgdGhpcy5fbGluayh0ICsgMiwgcS50KTtcblxuICAgICAgICAgICAgcS5wcmV2LnQgPSB0aGlzLl9sZWdhbGl6ZSh0ICsgMik7XG5cbiAgICAgICAgICAgIHRoaXMuaHVsbCA9IHJlbW92ZU5vZGUocSk7XG4gICAgICAgICAgICBxID0gcS5uZXh0O1xuICAgICAgICB9XG5cbiAgICAgICAgaWYgKHdhbGtCYWNrKSB7XG4gICAgICAgICAgICAvLyB3YWxrIGJhY2t3YXJkIGZyb20gdGhlIG90aGVyIHNpZGUsIGFkZGluZyBtb3JlIHRyaWFuZ2xlcyBhbmQgZmxpcHBpbmdcbiAgICAgICAgICAgIHEgPSBlLnByZXY7XG4gICAgICAgICAgICB3aGlsZSAoYXJlYSh4LCB5LCBxLnByZXYueCwgcS5wcmV2LnksIHEueCwgcS55KSA8IDApIHtcblxuICAgICAgICAgICAgICAgIHQgPSB0aGlzLl9hZGRUcmlhbmdsZShpLCBxLnByZXYpO1xuICAgICAgICAgICAgICAgIGFkamFjZW50W3RdID0gLTE7XG4gICAgICAgICAgICAgICAgdGhpcy5fbGluayh0ICsgMSwgcS50KTtcbiAgICAgICAgICAgICAgICB0aGlzLl9saW5rKHQgKyAyLCBxLnByZXYudCk7XG5cbiAgICAgICAgICAgICAgICB0aGlzLl9sZWdhbGl6ZSh0ICsgMik7XG5cbiAgICAgICAgICAgICAgICBxLnByZXYudCA9IHQ7XG4gICAgICAgICAgICAgICAgdGhpcy5odWxsID0gcmVtb3ZlTm9kZShxKTtcbiAgICAgICAgICAgICAgICBxID0gcS5wcmV2O1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG5cbiAgICAgICAgLy8gc2F2ZSB0aGUgdHdvIG5ldyBlZGdlcyBpbiB0aGUgaGFzaCB0YWJsZVxuICAgICAgICB0aGlzLl9oYXNoRWRnZShlKTtcbiAgICAgICAgdGhpcy5faGFzaEVkZ2UoZS5wcmV2KTtcbiAgICB9XG5cbiAgICAvLyB0cmltIHR5cGVkIHRyaWFuZ2xlIG1lc2ggYXJyYXlzXG4gICAgdGhpcy50cmlhbmdsZXMgPSB0cmlhbmdsZXMuc3ViYXJyYXkoMCwgdGhpcy50cmlhbmdsZXNMZW4pO1xuICAgIHRoaXMuYWRqYWNlbnQgPSBhZGphY2VudC5zdWJhcnJheSgwLCB0aGlzLnRyaWFuZ2xlc0xlbik7XG59XG5cbkRlbGF1bmF0b3IucHJvdG90eXBlID0ge1xuXG4gICAgX2hhc2hFZGdlOiBmdW5jdGlvbiAoZSkge1xuICAgICAgICB0aGlzLl9oYXNoW3RoaXMuX2hhc2hLZXkoZS54LCBlLnkpXSA9IGU7XG4gICAgfSxcblxuICAgIF9oYXNoS2V5OiBmdW5jdGlvbiAoeCwgeSkge1xuICAgICAgICB2YXIgZHggPSB4IC0gdGhpcy5fY3g7XG4gICAgICAgIHZhciBkeSA9IHkgLSB0aGlzLl9jeTtcbiAgICAgICAgLy8gdXNlIHBzZXVkby1hbmdsZTogYSBtZWFzdXJlIHRoYXQgbW9ub3RvbmljYWxseSBpbmNyZWFzZXNcbiAgICAgICAgLy8gd2l0aCByZWFsIGFuZ2xlLCBidXQgZG9lc24ndCByZXF1aXJlIGV4cGVuc2l2ZSB0cmlnb25vbWV0cnlcbiAgICAgICAgdmFyIHAgPSAxIC0gZHggLyAoTWF0aC5hYnMoZHgpICsgTWF0aC5hYnMoZHkpKTtcbiAgICAgICAgcmV0dXJuIE1hdGguZmxvb3IoKDIgKyAoZHkgPCAwID8gLXAgOiBwKSkgKiAodGhpcy5faGFzaFNpemUgLyA0KSk7XG4gICAgfSxcblxuICAgIF9sZWdhbGl6ZTogZnVuY3Rpb24gKGEpIHtcbiAgICAgICAgdmFyIHRyaWFuZ2xlcyA9IHRoaXMudHJpYW5nbGVzO1xuICAgICAgICB2YXIgY29vcmRzID0gdGhpcy5jb29yZHM7XG4gICAgICAgIHZhciBhZGphY2VudCA9IHRoaXMuYWRqYWNlbnQ7XG5cbiAgICAgICAgdmFyIGIgPSBhZGphY2VudFthXTtcblxuICAgICAgICB2YXIgYTAgPSBhIC0gYSAlIDM7XG4gICAgICAgIHZhciBiMCA9IGIgLSBiICUgMztcblxuICAgICAgICB2YXIgYWwgPSBhMCArIChhICsgMSkgJSAzO1xuICAgICAgICB2YXIgYXIgPSBhMCArIChhICsgMikgJSAzO1xuICAgICAgICB2YXIgYnIgPSBiMCArIChiICsgMSkgJSAzO1xuICAgICAgICB2YXIgYmwgPSBiMCArIChiICsgMikgJSAzO1xuXG4gICAgICAgIHZhciBwMCA9IHRyaWFuZ2xlc1thcl07XG4gICAgICAgIHZhciBwciA9IHRyaWFuZ2xlc1thXTtcbiAgICAgICAgdmFyIHBsID0gdHJpYW5nbGVzW2FsXTtcbiAgICAgICAgdmFyIHAxID0gdHJpYW5nbGVzW2JsXTtcblxuICAgICAgICB2YXIgaWxsZWdhbCA9IGluQ2lyY2xlKFxuICAgICAgICAgICAgY29vcmRzWzIgKiBwMF0sIGNvb3Jkc1syICogcDAgKyAxXSxcbiAgICAgICAgICAgIGNvb3Jkc1syICogcHJdLCBjb29yZHNbMiAqIHByICsgMV0sXG4gICAgICAgICAgICBjb29yZHNbMiAqIHBsXSwgY29vcmRzWzIgKiBwbCArIDFdLFxuICAgICAgICAgICAgY29vcmRzWzIgKiBwMV0sIGNvb3Jkc1syICogcDEgKyAxXSk7XG5cbiAgICAgICAgaWYgKGlsbGVnYWwpIHtcbiAgICAgICAgICAgIHRyaWFuZ2xlc1thXSA9IHAxO1xuICAgICAgICAgICAgdHJpYW5nbGVzW2JdID0gcDA7XG5cbiAgICAgICAgICAgIHRoaXMuX2xpbmsoYSwgYWRqYWNlbnRbYmxdKTtcbiAgICAgICAgICAgIHRoaXMuX2xpbmsoYiwgYWRqYWNlbnRbYXJdKTtcbiAgICAgICAgICAgIHRoaXMuX2xpbmsoYXIsIGJsKTtcblxuICAgICAgICAgICAgdGhpcy5fbGVnYWxpemUoYSk7XG4gICAgICAgICAgICByZXR1cm4gdGhpcy5fbGVnYWxpemUoYnIpO1xuICAgICAgICB9XG5cbiAgICAgICAgcmV0dXJuIGFyO1xuICAgIH0sXG5cbiAgICBfbGluazogZnVuY3Rpb24gKGEsIGIpIHtcbiAgICAgICAgdGhpcy5hZGphY2VudFthXSA9IGI7XG4gICAgICAgIGlmIChiICE9PSAtMSkgdGhpcy5hZGphY2VudFtiXSA9IGE7XG4gICAgfSxcblxuICAgIF9hZGRUcmlhbmdsZShpLCBlKSB7XG4gICAgICAgIHZhciB0ID0gdGhpcy50cmlhbmdsZXNMZW47XG4gICAgICAgIHRoaXMudHJpYW5nbGVzW3RdID0gZS5pO1xuICAgICAgICB0aGlzLnRyaWFuZ2xlc1t0ICsgMV0gPSBpO1xuICAgICAgICB0aGlzLnRyaWFuZ2xlc1t0ICsgMl0gPSBlLm5leHQuaTtcbiAgICAgICAgdGhpcy50cmlhbmdsZXNMZW4gKz0gMztcbiAgICAgICAgcmV0dXJuIHQ7XG4gICAgfVxufTtcblxuZnVuY3Rpb24gZGlzdChheCwgYXksIGJ4LCBieSkge1xuICAgIHZhciBkeCA9IGF4IC0gYng7XG4gICAgdmFyIGR5ID0gYXkgLSBieTtcbiAgICByZXR1cm4gZHggKiBkeCArIGR5ICogZHk7XG59XG5cbmZ1bmN0aW9uIGFyZWEocHgsIHB5LCBxeCwgcXksIHJ4LCByeSkge1xuICAgIHJldHVybiAocXkgLSBweSkgKiAocnggLSBxeCkgLSAocXggLSBweCkgKiAocnkgLSBxeSk7XG59XG5cbmZ1bmN0aW9uIGluQ2lyY2xlKGF4LCBheSwgYngsIGJ5LCBjeCwgY3ksIHB4LCBweSkge1xuICAgIGF4IC09IHB4O1xuICAgIGF5IC09IHB5O1xuICAgIGJ4IC09IHB4O1xuICAgIGJ5IC09IHB5O1xuICAgIGN4IC09IHB4O1xuICAgIGN5IC09IHB5O1xuXG4gICAgdmFyIGFwID0gYXggKiBheCArIGF5ICogYXk7XG4gICAgdmFyIGJwID0gYnggKiBieCArIGJ5ICogYnk7XG4gICAgdmFyIGNwID0gY3ggKiBjeCArIGN5ICogY3k7XG5cbiAgICB2YXIgZGV0ID0gYXggKiAoYnkgKiBjcCAtIGJwICogY3kpIC1cbiAgICAgICAgICAgICAgYXkgKiAoYnggKiBjcCAtIGJwICogY3gpICtcbiAgICAgICAgICAgICAgYXAgKiAoYnggKiBjeSAtIGJ5ICogY3gpO1xuXG4gICAgcmV0dXJuIGRldCA8IDA7XG59XG5cbmZ1bmN0aW9uIGNpcmN1bXJhZGl1cyhheCwgYXksIGJ4LCBieSwgY3gsIGN5KSB7XG4gICAgYnggLT0gYXg7XG4gICAgYnkgLT0gYXk7XG4gICAgY3ggLT0gYXg7XG4gICAgY3kgLT0gYXk7XG5cbiAgICB2YXIgYmwgPSBieCAqIGJ4ICsgYnkgKiBieTtcbiAgICB2YXIgY2wgPSBjeCAqIGN4ICsgY3kgKiBjeTtcblxuICAgIGlmIChibCA9PT0gMCB8fCBjbCA9PT0gMCkgcmV0dXJuIEluZmluaXR5O1xuXG4gICAgdmFyIGQgPSBieCAqIGN5IC0gYnkgKiBjeDtcbiAgICBpZiAoZCA9PT0gMCkgcmV0dXJuIEluZmluaXR5O1xuXG4gICAgdmFyIHggPSAoY3kgKiBibCAtIGJ5ICogY2wpICogMC41IC8gZDtcbiAgICB2YXIgeSA9IChieCAqIGNsIC0gY3ggKiBibCkgKiAwLjUgLyBkO1xuXG4gICAgcmV0dXJuIHggKiB4ICsgeSAqIHk7XG59XG5cbmZ1bmN0aW9uIGNpcmN1bWNlbnRlcihheCwgYXksIGJ4LCBieSwgY3gsIGN5KSB7XG4gICAgYnggLT0gYXg7XG4gICAgYnkgLT0gYXk7XG4gICAgY3ggLT0gYXg7XG4gICAgY3kgLT0gYXk7XG5cbiAgICB2YXIgYmwgPSBieCAqIGJ4ICsgYnkgKiBieTtcbiAgICB2YXIgY2wgPSBjeCAqIGN4ICsgY3kgKiBjeTtcblxuICAgIHZhciBkID0gYnggKiBjeSAtIGJ5ICogY3g7XG5cbiAgICB2YXIgeCA9IChjeSAqIGJsIC0gYnkgKiBjbCkgKiAwLjUgLyBkO1xuICAgIHZhciB5ID0gKGJ4ICogY2wgLSBjeCAqIGJsKSAqIDAuNSAvIGQ7XG5cbiAgICByZXR1cm4ge1xuICAgICAgICB4OiBheCArIHgsXG4gICAgICAgIHk6IGF5ICsgeVxuICAgIH07XG59XG5cbi8vIGNyZWF0ZSBhIG5ldyBub2RlIGluIGEgZG91Ymx5IGxpbmtlZCBsaXN0XG5mdW5jdGlvbiBpbnNlcnROb2RlKGNvb3JkcywgaSwgcHJldikge1xuICAgIHZhciBub2RlID0ge1xuICAgICAgICBpOiBpLFxuICAgICAgICB4OiBjb29yZHNbMiAqIGldLFxuICAgICAgICB5OiBjb29yZHNbMiAqIGkgKyAxXSxcbiAgICAgICAgdDogMCxcbiAgICAgICAgcHJldjogbnVsbCxcbiAgICAgICAgbmV4dDogbnVsbCxcbiAgICAgICAgcmVtb3ZlZDogZmFsc2VcbiAgICB9O1xuXG4gICAgaWYgKCFwcmV2KSB7XG4gICAgICAgIG5vZGUucHJldiA9IG5vZGU7XG4gICAgICAgIG5vZGUubmV4dCA9IG5vZGU7XG5cbiAgICB9IGVsc2Uge1xuICAgICAgICBub2RlLm5leHQgPSBwcmV2Lm5leHQ7XG4gICAgICAgIG5vZGUucHJldiA9IHByZXY7XG4gICAgICAgIHByZXYubmV4dC5wcmV2ID0gbm9kZTtcbiAgICAgICAgcHJldi5uZXh0ID0gbm9kZTtcbiAgICB9XG4gICAgcmV0dXJuIG5vZGU7XG59XG5cbmZ1bmN0aW9uIHJlbW92ZU5vZGUobm9kZSkge1xuICAgIG5vZGUucHJldi5uZXh0ID0gbm9kZS5uZXh0O1xuICAgIG5vZGUubmV4dC5wcmV2ID0gbm9kZS5wcmV2O1xuICAgIG5vZGUucmVtb3ZlZCA9IHRydWU7XG4gICAgcmV0dXJuIG5vZGUucHJldjtcbn1cblxuZnVuY3Rpb24gcXVpY2tzb3J0KGlkcywgY29vcmRzLCBsZWZ0LCByaWdodCwgY3gsIGN5KSB7XG4gICAgdmFyIGksIGosIHRlbXA7XG5cbiAgICBpZiAocmlnaHQgLSBsZWZ0IDw9IDIwKSB7XG4gICAgICAgIGZvciAoaSA9IGxlZnQgKyAxOyBpIDw9IHJpZ2h0OyBpKyspIHtcbiAgICAgICAgICAgIHRlbXAgPSBpZHNbaV07XG4gICAgICAgICAgICBqID0gaSAtIDE7XG4gICAgICAgICAgICB3aGlsZSAoaiA+PSBsZWZ0ICYmIGNvbXBhcmUoY29vcmRzLCBpZHNbal0sIHRlbXAsIGN4LCBjeSkgPiAwKSBpZHNbaiArIDFdID0gaWRzW2otLV07XG4gICAgICAgICAgICBpZHNbaiArIDFdID0gdGVtcDtcbiAgICAgICAgfVxuICAgIH0gZWxzZSB7XG4gICAgICAgIHZhciBtZWRpYW4gPSAobGVmdCArIHJpZ2h0KSA+PiAxO1xuICAgICAgICBpID0gbGVmdCArIDE7XG4gICAgICAgIGogPSByaWdodDtcbiAgICAgICAgc3dhcChpZHMsIG1lZGlhbiwgaSk7XG4gICAgICAgIGlmIChjb21wYXJlKGNvb3JkcywgaWRzW2xlZnRdLCBpZHNbcmlnaHRdLCBjeCwgY3kpID4gMCkgc3dhcChpZHMsIGxlZnQsIHJpZ2h0KTtcbiAgICAgICAgaWYgKGNvbXBhcmUoY29vcmRzLCBpZHNbaV0sIGlkc1tyaWdodF0sIGN4LCBjeSkgPiAwKSBzd2FwKGlkcywgaSwgcmlnaHQpO1xuICAgICAgICBpZiAoY29tcGFyZShjb29yZHMsIGlkc1tsZWZ0XSwgaWRzW2ldLCBjeCwgY3kpID4gMCkgc3dhcChpZHMsIGxlZnQsIGkpO1xuXG4gICAgICAgIHRlbXAgPSBpZHNbaV07XG4gICAgICAgIHdoaWxlICh0cnVlKSB7XG4gICAgICAgICAgICBkbyBpKys7IHdoaWxlIChjb21wYXJlKGNvb3JkcywgaWRzW2ldLCB0ZW1wLCBjeCwgY3kpIDwgMCk7XG4gICAgICAgICAgICBkbyBqLS07IHdoaWxlIChjb21wYXJlKGNvb3JkcywgaWRzW2pdLCB0ZW1wLCBjeCwgY3kpID4gMCk7XG4gICAgICAgICAgICBpZiAoaiA8IGkpIGJyZWFrO1xuICAgICAgICAgICAgc3dhcChpZHMsIGksIGopO1xuICAgICAgICB9XG4gICAgICAgIGlkc1tsZWZ0ICsgMV0gPSBpZHNbal07XG4gICAgICAgIGlkc1tqXSA9IHRlbXA7XG5cbiAgICAgICAgaWYgKHJpZ2h0IC0gaSArIDEgPj0gaiAtIGxlZnQpIHtcbiAgICAgICAgICAgIHF1aWNrc29ydChpZHMsIGNvb3JkcywgaSwgcmlnaHQsIGN4LCBjeSk7XG4gICAgICAgICAgICBxdWlja3NvcnQoaWRzLCBjb29yZHMsIGxlZnQsIGogLSAxLCBjeCwgY3kpO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgcXVpY2tzb3J0KGlkcywgY29vcmRzLCBsZWZ0LCBqIC0gMSwgY3gsIGN5KTtcbiAgICAgICAgICAgIHF1aWNrc29ydChpZHMsIGNvb3JkcywgaSwgcmlnaHQsIGN4LCBjeSk7XG4gICAgICAgIH1cbiAgICB9XG59XG5cbmZ1bmN0aW9uIGNvbXBhcmUoY29vcmRzLCBpLCBqLCBjeCwgY3kpIHtcbiAgICB2YXIgZDEgPSBkaXN0KGNvb3Jkc1syICogaV0sIGNvb3Jkc1syICogaSArIDFdLCBjeCwgY3kpO1xuICAgIHZhciBkMiA9IGRpc3QoY29vcmRzWzIgKiBqXSwgY29vcmRzWzIgKiBqICsgMV0sIGN4LCBjeSk7XG4gICAgcmV0dXJuIChkMSAtIGQyKSB8fCAoY29vcmRzWzIgKiBpXSAtIGNvb3Jkc1syICogal0pIHx8IChjb29yZHNbMiAqIGkgKyAxXSAtIGNvb3Jkc1syICogaiArIDFdKTtcbn1cblxuZnVuY3Rpb24gc3dhcChhcnIsIGksIGopIHtcbiAgICB2YXIgdG1wID0gYXJyW2ldO1xuICAgIGFycltpXSA9IGFycltqXTtcbiAgICBhcnJbal0gPSB0bXA7XG59XG5cbmZ1bmN0aW9uIGRlZmF1bHRHZXRYKHApIHtcbiAgICByZXR1cm4gcFswXTtcbn1cbmZ1bmN0aW9uIGRlZmF1bHRHZXRZKHApIHtcbiAgICByZXR1cm4gcFsxXTtcbn1cbiJdfQ== | |
require=(function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(require,module,exports){ | |
module.exports = function (a, b) { | |
var sum = 0 | |
var n | |
for (n = 0; n < a.length; n++) { | |
sum += Math.pow(a[n] - b[n], 2) | |
} | |
return sum | |
} | |
},{}],"euclidean-distance":[function(require,module,exports){ | |
// http://en.wikipedia.org/wiki/Euclidean_distance#Three_dimensions | |
var distanceSquared = require('./squared') | |
module.exports = function (a, b) { | |
return Math.sqrt(distanceSquared(a,b)) | |
} | |
},{"./squared":1}]},{},[]) | |
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uL2hvbWUvYWRtaW4vYnJvd3NlcmlmeS1jZG4vbm9kZV9tb2R1bGVzL2Jyb3dzZXJpZnkvbm9kZV9tb2R1bGVzL2Jyb3dzZXItcGFjay9fcHJlbHVkZS5qcyIsInNxdWFyZWQuanMiLCJldWNsaWRlYW4tZGlzdGFuY2UiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUE7QUNBQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDUkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSIsImZpbGUiOiJnZW5lcmF0ZWQuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlc0NvbnRlbnQiOlsiKGZ1bmN0aW9uIGUodCxuLHIpe2Z1bmN0aW9uIHMobyx1KXtpZighbltvXSl7aWYoIXRbb10pe3ZhciBhPXR5cGVvZiByZXF1aXJlPT1cImZ1bmN0aW9uXCImJnJlcXVpcmU7aWYoIXUmJmEpcmV0dXJuIGEobywhMCk7aWYoaSlyZXR1cm4gaShvLCEwKTt2YXIgZj1uZXcgRXJyb3IoXCJDYW5ub3QgZmluZCBtb2R1bGUgJ1wiK28rXCInXCIpO3Rocm93IGYuY29kZT1cIk1PRFVMRV9OT1RfRk9VTkRcIixmfXZhciBsPW5bb109e2V4cG9ydHM6e319O3Rbb11bMF0uY2FsbChsLmV4cG9ydHMsZnVuY3Rpb24oZSl7dmFyIG49dFtvXVsxXVtlXTtyZXR1cm4gcyhuP246ZSl9LGwsbC5leHBvcnRzLGUsdCxuLHIpfXJldHVybiBuW29dLmV4cG9ydHN9dmFyIGk9dHlwZW9mIHJlcXVpcmU9PVwiZnVuY3Rpb25cIiYmcmVxdWlyZTtmb3IodmFyIG89MDtvPHIubGVuZ3RoO28rKylzKHJbb10pO3JldHVybiBzfSkiLCJtb2R1bGUuZXhwb3J0cyA9IGZ1bmN0aW9uIChhLCBiKSB7XG4gIHZhciBzdW0gPSAwXG4gIHZhciBuXG4gIGZvciAobiA9IDA7IG4gPCBhLmxlbmd0aDsgbisrKSB7XG4gICAgc3VtICs9IE1hdGgucG93KGFbbl0gLSBiW25dLCAyKVxuICB9XG4gIHJldHVybiBzdW1cbn1cbiIsIi8vIGh0dHA6Ly9lbi53aWtpcGVkaWEub3JnL3dpa2kvRXVjbGlkZWFuX2Rpc3RhbmNlI1RocmVlX2RpbWVuc2lvbnNcblxudmFyIGRpc3RhbmNlU3F1YXJlZCA9IHJlcXVpcmUoJy4vc3F1YXJlZCcpXG5cbm1vZHVsZS5leHBvcnRzID0gZnVuY3Rpb24gKGEsIGIpIHtcbiAgcmV0dXJuIE1hdGguc3FydChkaXN0YW5jZVNxdWFyZWQoYSxiKSlcbn1cbiJdfQ== | |
var Simplex = require('perlin-simplex') | |
var Delaunator = require('delaunator') | |
var getDistance = require('euclidean-distance') | |
var simplex = new Simplex() | |
var SPEED = 0.001 | |
var N_POINTS = 200 | |
document.body.style.background = 'rgb(20, 20, 20)' | |
var stage = createStage() | |
document.body.appendChild(stage) | |
var points = createPoints(N_POINTS) | |
var triangles = createTrianges(points) | |
stage.appendChild(triangles.el) | |
window.requestAnimationFrame(updateLoop) | |
function updateLoop () { | |
window.requestAnimationFrame(updateLoop) | |
points.forEach(function (point) { point.update() }) | |
triangles.update(points) | |
} | |
function createPoints (n) { | |
var points = [] | |
for (var i = 0; i < n; i++) { | |
points.push({ | |
x: Math.random(), | |
y: Math.random(), | |
theta: Math.random() * 2 * Math.PI, | |
update: updatePoint | |
}) | |
} | |
return points | |
} | |
function updatePoint () { | |
var nx = this.x * 5 | |
var ny = this.y * 10 | |
var nz = Date.now() / 1000 | |
var s = simplex.noise3d(nx, ny, nz) | |
var theta = s * 2 * Math.PI | |
this.theta = (0.01 * theta) + (0.99 * this.theta) | |
this.x += SPEED * Math.cos(this.theta) | |
this.y += SPEED * Math.sin(this.theta) | |
this.x = mod(this.x, 1) | |
this.y = mod(this.y, 1) | |
} | |
function createTrianges (points) { | |
var viewBox = [0, 0, 1, 1].join(' ') | |
var pathData = createPathData(points) | |
var parent = document.createElement('div') | |
parent.style.width = '100%' | |
parent.style.height = '100%' | |
parent.innerHTML = ` | |
<svg xmlns='http://www.w3.org/svg/2000' | |
viewBox='${viewBox}' | |
width='100%' | |
height='100%' | |
stroke='none' | |
fill='none'> | |
${pathData} | |
</svg> | |
` | |
var svg = parent.children[0] | |
return { | |
el: parent, | |
update: function (points) { | |
svg.innerHTML = createPathData(points) | |
} | |
} | |
} | |
function createPathData (points) { | |
var coords = points.map(function (point) { | |
return [point.x, point.y] | |
}) | |
var triangles = new Delaunator(coords).triangles | |
var pathData = [] | |
for (var i = 0; i < triangles.length; i += 3) { | |
pathData.push(createTrianglePath( | |
coords[triangles[i + 0]], | |
coords[triangles[i + 1]], | |
coords[triangles[i + 2]] | |
)) | |
} | |
return pathData.join('\n') | |
} | |
function createTrianglePath (pa, pb, pc) { | |
var x0 = pa[0] | |
var y0 = pa[1] | |
var x1 = pb[0] | |
var y1 = pb[1] | |
var x2 = pc[0] | |
var y2 = pc[1] | |
var d = [ | |
'M', x0, y0, | |
'L', x1, y1, | |
'L', x2, y2, | |
'L', x0, y0 | |
].join(' ') | |
var eq = equalness(x0, y0, x1, y1, x2, y2) | |
eq = eq * eq | |
var b = Math.floor(30 + (eq * 130)) | |
var fill = `rgb(${b}, ${b}, ${b})` | |
return `<path d='${d}' fill='${fill}' stroke='none' />` | |
} | |
function equalness (x0, y0, x1, y1, x2, y2) { | |
var a = getDistance([x0, y0], [x1, y1]) | |
var b = getDistance([x0, y0], [x2, y2]) | |
var c = getDistance([x2, y2], [x1, y1]) | |
var diff = Math.abs(a - b) + Math.abs(a - c) + Math.abs(b - c) | |
return 1 - (diff / (a + b + c)) | |
} | |
function createStage (w, h) { | |
var stage = document.createElement('div') | |
stage.style.position = 'absolute' | |
stage.style.top = '10%' | |
stage.style.left = '10%' | |
stage.style.width = '80%' | |
stage.style.height = '80%' | |
return stage | |
} | |
function mod (a, n) { | |
return ((a % n) + n) % n | |
} | |
;}, 0) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{ | |
"name": "requirebin-sketch", | |
"version": "1.0.0", | |
"dependencies": { | |
"perlin-simplex": "0.0.2", | |
"delaunator": "1.0.2", | |
"euclidean-distance": "1.0.0" | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!-- contents of this file will be placed inside the <body> --> |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!-- contents of this file will be placed inside the <head> --> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment