Comparing version 1.1.0 to 1.1.1
1174
knotess.js
@@ -1,1173 +0,1 @@ | ||
(function (global, factory) { | ||
typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() : | ||
typeof define === 'function' && define.amd ? define(factory) : | ||
(global.Knotess = factory()); | ||
}(this, (function () { 'use strict'; | ||
/** | ||
* Common utilities | ||
* @module glMatrix | ||
*/ | ||
// Configuration Constants | ||
var EPSILON = 0.000001; | ||
var ARRAY_TYPE = typeof Float32Array !== 'undefined' ? Float32Array : Array; | ||
var degree = Math.PI / 180; | ||
/** | ||
* 3x3 Matrix | ||
* @module mat3 | ||
*/ | ||
/** | ||
* Creates a new identity mat3 | ||
* | ||
* @returns {mat3} a new 3x3 matrix | ||
*/ | ||
function create$2() { | ||
var out = new ARRAY_TYPE(9); | ||
if (ARRAY_TYPE != Float32Array) { | ||
out[1] = 0; | ||
out[2] = 0; | ||
out[3] = 0; | ||
out[5] = 0; | ||
out[6] = 0; | ||
out[7] = 0; | ||
} | ||
out[0] = 1; | ||
out[4] = 1; | ||
out[8] = 1; | ||
return out; | ||
} | ||
/** | ||
* 3 Dimensional Vector | ||
* @module vec3 | ||
*/ | ||
/** | ||
* Creates a new, empty vec3 | ||
* | ||
* @returns {vec3} a new 3D vector | ||
*/ | ||
function create$4() { | ||
var out = new ARRAY_TYPE(3); | ||
if (ARRAY_TYPE != Float32Array) { | ||
out[0] = 0; | ||
out[1] = 0; | ||
out[2] = 0; | ||
} | ||
return out; | ||
} | ||
/** | ||
* Creates a new vec3 initialized with values from an existing vector | ||
* | ||
* @param {vec3} a vector to clone | ||
* @returns {vec3} a new 3D vector | ||
*/ | ||
function clone$4(a) { | ||
var out = new ARRAY_TYPE(3); | ||
out[0] = a[0]; | ||
out[1] = a[1]; | ||
out[2] = a[2]; | ||
return out; | ||
} | ||
/** | ||
* Calculates the length of a vec3 | ||
* | ||
* @param {vec3} a vector to calculate length of | ||
* @returns {Number} length of a | ||
*/ | ||
function length(a) { | ||
var x = a[0]; | ||
var y = a[1]; | ||
var z = a[2]; | ||
return Math.sqrt(x * x + y * y + z * z); | ||
} | ||
/** | ||
* Creates a new vec3 initialized with the given values | ||
* | ||
* @param {Number} x X component | ||
* @param {Number} y Y component | ||
* @param {Number} z Z component | ||
* @returns {vec3} a new 3D vector | ||
*/ | ||
function fromValues$4(x, y, z) { | ||
var out = new ARRAY_TYPE(3); | ||
out[0] = x; | ||
out[1] = y; | ||
out[2] = z; | ||
return out; | ||
} | ||
/** | ||
* Copy the values from one vec3 to another | ||
* | ||
* @param {vec3} out the receiving vector | ||
* @param {vec3} a the source vector | ||
* @returns {vec3} out | ||
*/ | ||
function copy$4(out, a) { | ||
out[0] = a[0]; | ||
out[1] = a[1]; | ||
out[2] = a[2]; | ||
return out; | ||
} | ||
/** | ||
* Adds two vec3's | ||
* | ||
* @param {vec3} out the receiving vector | ||
* @param {vec3} a the first operand | ||
* @param {vec3} b the second operand | ||
* @returns {vec3} out | ||
*/ | ||
function add$4(out, a, b) { | ||
out[0] = a[0] + b[0]; | ||
out[1] = a[1] + b[1]; | ||
out[2] = a[2] + b[2]; | ||
return out; | ||
} | ||
/** | ||
* Scales a vec3 by a scalar number | ||
* | ||
* @param {vec3} out the receiving vector | ||
* @param {vec3} a the vector to scale | ||
* @param {Number} b amount to scale the vector by | ||
* @returns {vec3} out | ||
*/ | ||
function scale$4(out, a, b) { | ||
out[0] = a[0] * b; | ||
out[1] = a[1] * b; | ||
out[2] = a[2] * b; | ||
return out; | ||
} | ||
/** | ||
* Normalize a vec3 | ||
* | ||
* @param {vec3} out the receiving vector | ||
* @param {vec3} a vector to normalize | ||
* @returns {vec3} out | ||
*/ | ||
function normalize(out, a) { | ||
var x = a[0]; | ||
var y = a[1]; | ||
var z = a[2]; | ||
var len = x * x + y * y + z * z; | ||
if (len > 0) { | ||
//TODO: evaluate use of glm_invsqrt here? | ||
len = 1 / Math.sqrt(len); | ||
out[0] = a[0] * len; | ||
out[1] = a[1] * len; | ||
out[2] = a[2] * len; | ||
} | ||
return out; | ||
} | ||
/** | ||
* Calculates the dot product of two vec3's | ||
* | ||
* @param {vec3} a the first operand | ||
* @param {vec3} b the second operand | ||
* @returns {Number} dot product of a and b | ||
*/ | ||
function dot(a, b) { | ||
return a[0] * b[0] + a[1] * b[1] + a[2] * b[2]; | ||
} | ||
/** | ||
* Computes the cross product of two vec3's | ||
* | ||
* @param {vec3} out the receiving vector | ||
* @param {vec3} a the first operand | ||
* @param {vec3} b the second operand | ||
* @returns {vec3} out | ||
*/ | ||
function cross(out, a, b) { | ||
var ax = a[0], | ||
ay = a[1], | ||
az = a[2]; | ||
var bx = b[0], | ||
by = b[1], | ||
bz = b[2]; | ||
out[0] = ay * bz - az * by; | ||
out[1] = az * bx - ax * bz; | ||
out[2] = ax * by - ay * bx; | ||
return out; | ||
} | ||
/** | ||
* Performs a linear interpolation between two vec3's | ||
* | ||
* @param {vec3} out the receiving vector | ||
* @param {vec3} a the first operand | ||
* @param {vec3} b the second operand | ||
* @param {Number} t interpolation amount, in the range [0-1], between the two inputs | ||
* @returns {vec3} out | ||
*/ | ||
function lerp(out, a, b, t) { | ||
var ax = a[0]; | ||
var ay = a[1]; | ||
var az = a[2]; | ||
out[0] = ax + t * (b[0] - ax); | ||
out[1] = ay + t * (b[1] - ay); | ||
out[2] = az + t * (b[2] - az); | ||
return out; | ||
} | ||
/** | ||
* Transforms the vec3 with a mat3. | ||
* | ||
* @param {vec3} out the receiving vector | ||
* @param {vec3} a the vector to transform | ||
* @param {mat3} m the 3x3 matrix to transform with | ||
* @returns {vec3} out | ||
*/ | ||
function transformMat3(out, a, m) { | ||
var x = a[0], | ||
y = a[1], | ||
z = a[2]; | ||
out[0] = x * m[0] + y * m[3] + z * m[6]; | ||
out[1] = x * m[1] + y * m[4] + z * m[7]; | ||
out[2] = x * m[2] + y * m[5] + z * m[8]; | ||
return out; | ||
} | ||
/** | ||
* Alias for {@link vec3.length} | ||
* @function | ||
*/ | ||
var len = length; | ||
/** | ||
* Perform some operation over an array of vec3s. | ||
* | ||
* @param {Array} a the array of vectors to iterate over | ||
* @param {Number} stride Number of elements between the start of each vec3. If 0 assumes tightly packed | ||
* @param {Number} offset Number of elements to skip at the beginning of the array | ||
* @param {Number} count Number of vec3s to iterate over. If 0 iterates over entire array | ||
* @param {Function} fn Function to call for each vector in the array | ||
* @param {Object} [arg] additional argument to pass to fn | ||
* @returns {Array} a | ||
* @function | ||
*/ | ||
var forEach = function () { | ||
var vec = create$4(); | ||
return function (a, stride, offset, count, fn, arg) { | ||
var i = void 0, | ||
l = void 0; | ||
if (!stride) { | ||
stride = 3; | ||
} | ||
if (!offset) { | ||
offset = 0; | ||
} | ||
if (count) { | ||
l = Math.min(count * stride + offset, a.length); | ||
} else { | ||
l = a.length; | ||
} | ||
for (i = offset; i < l; i += stride) { | ||
vec[0] = a[i];vec[1] = a[i + 1];vec[2] = a[i + 2]; | ||
fn(vec, vec, arg); | ||
a[i] = vec[0];a[i + 1] = vec[1];a[i + 2] = vec[2]; | ||
} | ||
return a; | ||
}; | ||
}(); | ||
/** | ||
* 4 Dimensional Vector | ||
* @module vec4 | ||
*/ | ||
/** | ||
* Creates a new, empty vec4 | ||
* | ||
* @returns {vec4} a new 4D vector | ||
*/ | ||
function create$5() { | ||
var out = new ARRAY_TYPE(4); | ||
if (ARRAY_TYPE != Float32Array) { | ||
out[0] = 0; | ||
out[1] = 0; | ||
out[2] = 0; | ||
out[3] = 0; | ||
} | ||
return out; | ||
} | ||
/** | ||
* Normalize a vec4 | ||
* | ||
* @param {vec4} out the receiving vector | ||
* @param {vec4} a vector to normalize | ||
* @returns {vec4} out | ||
*/ | ||
function normalize$1(out, a) { | ||
var x = a[0]; | ||
var y = a[1]; | ||
var z = a[2]; | ||
var w = a[3]; | ||
var len = x * x + y * y + z * z + w * w; | ||
if (len > 0) { | ||
len = 1 / Math.sqrt(len); | ||
out[0] = x * len; | ||
out[1] = y * len; | ||
out[2] = z * len; | ||
out[3] = w * len; | ||
} | ||
return out; | ||
} | ||
/** | ||
* Perform some operation over an array of vec4s. | ||
* | ||
* @param {Array} a the array of vectors to iterate over | ||
* @param {Number} stride Number of elements between the start of each vec4. If 0 assumes tightly packed | ||
* @param {Number} offset Number of elements to skip at the beginning of the array | ||
* @param {Number} count Number of vec4s to iterate over. If 0 iterates over entire array | ||
* @param {Function} fn Function to call for each vector in the array | ||
* @param {Object} [arg] additional argument to pass to fn | ||
* @returns {Array} a | ||
* @function | ||
*/ | ||
var forEach$1 = function () { | ||
var vec = create$5(); | ||
return function (a, stride, offset, count, fn, arg) { | ||
var i = void 0, | ||
l = void 0; | ||
if (!stride) { | ||
stride = 4; | ||
} | ||
if (!offset) { | ||
offset = 0; | ||
} | ||
if (count) { | ||
l = Math.min(count * stride + offset, a.length); | ||
} else { | ||
l = a.length; | ||
} | ||
for (i = offset; i < l; i += stride) { | ||
vec[0] = a[i];vec[1] = a[i + 1];vec[2] = a[i + 2];vec[3] = a[i + 3]; | ||
fn(vec, vec, arg); | ||
a[i] = vec[0];a[i + 1] = vec[1];a[i + 2] = vec[2];a[i + 3] = vec[3]; | ||
} | ||
return a; | ||
}; | ||
}(); | ||
/** | ||
* Quaternion | ||
* @module quat | ||
*/ | ||
/** | ||
* Creates a new identity quat | ||
* | ||
* @returns {quat} a new quaternion | ||
*/ | ||
function create$6() { | ||
var out = new ARRAY_TYPE(4); | ||
if (ARRAY_TYPE != Float32Array) { | ||
out[0] = 0; | ||
out[1] = 0; | ||
out[2] = 0; | ||
} | ||
out[3] = 1; | ||
return out; | ||
} | ||
/** | ||
* Sets a quat from the given angle and rotation axis, | ||
* then returns it. | ||
* | ||
* @param {quat} out the receiving quaternion | ||
* @param {vec3} axis the axis around which to rotate | ||
* @param {Number} rad the angle in radians | ||
* @returns {quat} out | ||
**/ | ||
function setAxisAngle(out, axis, rad) { | ||
rad = rad * 0.5; | ||
var s = Math.sin(rad); | ||
out[0] = s * axis[0]; | ||
out[1] = s * axis[1]; | ||
out[2] = s * axis[2]; | ||
out[3] = Math.cos(rad); | ||
return out; | ||
} | ||
/** | ||
* Performs a spherical linear interpolation between two quat | ||
* | ||
* @param {quat} out the receiving quaternion | ||
* @param {quat} a the first operand | ||
* @param {quat} b the second operand | ||
* @param {Number} t interpolation amount, in the range [0-1], between the two inputs | ||
* @returns {quat} out | ||
*/ | ||
function slerp(out, a, b, t) { | ||
// benchmarks: | ||
// http://jsperf.com/quaternion-slerp-implementations | ||
var ax = a[0], | ||
ay = a[1], | ||
az = a[2], | ||
aw = a[3]; | ||
var bx = b[0], | ||
by = b[1], | ||
bz = b[2], | ||
bw = b[3]; | ||
var omega = void 0, | ||
cosom = void 0, | ||
sinom = void 0, | ||
scale0 = void 0, | ||
scale1 = void 0; | ||
// calc cosine | ||
cosom = ax * bx + ay * by + az * bz + aw * bw; | ||
// adjust signs (if necessary) | ||
if (cosom < 0.0) { | ||
cosom = -cosom; | ||
bx = -bx; | ||
by = -by; | ||
bz = -bz; | ||
bw = -bw; | ||
} | ||
// calculate coefficients | ||
if (1.0 - cosom > EPSILON) { | ||
// standard case (slerp) | ||
omega = Math.acos(cosom); | ||
sinom = Math.sin(omega); | ||
scale0 = Math.sin((1.0 - t) * omega) / sinom; | ||
scale1 = Math.sin(t * omega) / sinom; | ||
} else { | ||
// "from" and "to" quaternions are very close | ||
// ... so we can do a linear interpolation | ||
scale0 = 1.0 - t; | ||
scale1 = t; | ||
} | ||
// calculate final values | ||
out[0] = scale0 * ax + scale1 * bx; | ||
out[1] = scale0 * ay + scale1 * by; | ||
out[2] = scale0 * az + scale1 * bz; | ||
out[3] = scale0 * aw + scale1 * bw; | ||
return out; | ||
} | ||
/** | ||
* Creates a quaternion from the given 3x3 rotation matrix. | ||
* | ||
* NOTE: The resultant quaternion is not normalized, so you should be sure | ||
* to renormalize the quaternion yourself where necessary. | ||
* | ||
* @param {quat} out the receiving quaternion | ||
* @param {mat3} m rotation matrix | ||
* @returns {quat} out | ||
* @function | ||
*/ | ||
function fromMat3(out, m) { | ||
// Algorithm in Ken Shoemake's article in 1987 SIGGRAPH course notes | ||
// article "Quaternion Calculus and Fast Animation". | ||
var fTrace = m[0] + m[4] + m[8]; | ||
var fRoot = void 0; | ||
if (fTrace > 0.0) { | ||
// |w| > 1/2, may as well choose w > 1/2 | ||
fRoot = Math.sqrt(fTrace + 1.0); // 2w | ||
out[3] = 0.5 * fRoot; | ||
fRoot = 0.5 / fRoot; // 1/(4w) | ||
out[0] = (m[5] - m[7]) * fRoot; | ||
out[1] = (m[6] - m[2]) * fRoot; | ||
out[2] = (m[1] - m[3]) * fRoot; | ||
} else { | ||
// |w| <= 1/2 | ||
var i = 0; | ||
if (m[4] > m[0]) i = 1; | ||
if (m[8] > m[i * 3 + i]) i = 2; | ||
var j = (i + 1) % 3; | ||
var k = (i + 2) % 3; | ||
fRoot = Math.sqrt(m[i * 3 + i] - m[j * 3 + j] - m[k * 3 + k] + 1.0); | ||
out[i] = 0.5 * fRoot; | ||
fRoot = 0.5 / fRoot; | ||
out[3] = (m[j * 3 + k] - m[k * 3 + j]) * fRoot; | ||
out[j] = (m[j * 3 + i] + m[i * 3 + j]) * fRoot; | ||
out[k] = (m[k * 3 + i] + m[i * 3 + k]) * fRoot; | ||
} | ||
return out; | ||
} | ||
/** | ||
* Normalize a quat | ||
* | ||
* @param {quat} out the receiving quaternion | ||
* @param {quat} a quaternion to normalize | ||
* @returns {quat} out | ||
* @function | ||
*/ | ||
var normalize$2 = normalize$1; | ||
/** | ||
* Sets a quaternion to represent the shortest rotation from one | ||
* vector to another. | ||
* | ||
* Both vectors are assumed to be unit length. | ||
* | ||
* @param {quat} out the receiving quaternion. | ||
* @param {vec3} a the initial vector | ||
* @param {vec3} b the destination vector | ||
* @returns {quat} out | ||
*/ | ||
var rotationTo = function () { | ||
var tmpvec3 = create$4(); | ||
var xUnitVec3 = fromValues$4(1, 0, 0); | ||
var yUnitVec3 = fromValues$4(0, 1, 0); | ||
return function (out, a, b) { | ||
var dot$$1 = dot(a, b); | ||
if (dot$$1 < -0.999999) { | ||
cross(tmpvec3, xUnitVec3, a); | ||
if (len(tmpvec3) < 0.000001) cross(tmpvec3, yUnitVec3, a); | ||
normalize(tmpvec3, tmpvec3); | ||
setAxisAngle(out, tmpvec3, Math.PI); | ||
return out; | ||
} else if (dot$$1 > 0.999999) { | ||
out[0] = 0; | ||
out[1] = 0; | ||
out[2] = 0; | ||
out[3] = 1; | ||
return out; | ||
} else { | ||
cross(tmpvec3, a, b); | ||
out[0] = tmpvec3[0]; | ||
out[1] = tmpvec3[1]; | ||
out[2] = tmpvec3[2]; | ||
out[3] = 1 + dot$$1; | ||
return normalize$2(out, out); | ||
} | ||
}; | ||
}(); | ||
/** | ||
* Performs a spherical linear interpolation with two control points | ||
* | ||
* @param {quat} out the receiving quaternion | ||
* @param {quat} a the first operand | ||
* @param {quat} b the second operand | ||
* @param {quat} c the third operand | ||
* @param {quat} d the fourth operand | ||
* @param {Number} t interpolation amount, in the range [0-1], between the two inputs | ||
* @returns {quat} out | ||
*/ | ||
var sqlerp = function () { | ||
var temp1 = create$6(); | ||
var temp2 = create$6(); | ||
return function (out, a, b, c, d, t) { | ||
slerp(temp1, a, d, t); | ||
slerp(temp2, b, c, t); | ||
slerp(out, temp1, temp2, 2 * t * (1 - t)); | ||
return out; | ||
}; | ||
}(); | ||
/** | ||
* Sets the specified quaternion with values corresponding to the given | ||
* axes. Each axis is a vec3 and is expected to be unit length and | ||
* perpendicular to all other specified axes. | ||
* | ||
* @param {vec3} view the vector representing the viewing direction | ||
* @param {vec3} right the vector representing the local "right" direction | ||
* @param {vec3} up the vector representing the local "up" direction | ||
* @returns {quat} out | ||
*/ | ||
var setAxes = function () { | ||
var matr = create$2(); | ||
return function (out, view, right, up) { | ||
matr[0] = right[0]; | ||
matr[3] = right[1]; | ||
matr[6] = right[2]; | ||
matr[1] = up[0]; | ||
matr[4] = up[1]; | ||
matr[7] = up[2]; | ||
matr[2] = -view[0]; | ||
matr[5] = -view[1]; | ||
matr[8] = -view[2]; | ||
return normalize$2(out, fromMat3(out, matr)); | ||
}; | ||
}(); | ||
/** | ||
* 2 Dimensional Vector | ||
* @module vec2 | ||
*/ | ||
/** | ||
* Creates a new, empty vec2 | ||
* | ||
* @returns {vec2} a new 2D vector | ||
*/ | ||
function create$8() { | ||
var out = new ARRAY_TYPE(2); | ||
if (ARRAY_TYPE != Float32Array) { | ||
out[0] = 0; | ||
out[1] = 0; | ||
} | ||
return out; | ||
} | ||
/** | ||
* Perform some operation over an array of vec2s. | ||
* | ||
* @param {Array} a the array of vectors to iterate over | ||
* @param {Number} stride Number of elements between the start of each vec2. If 0 assumes tightly packed | ||
* @param {Number} offset Number of elements to skip at the beginning of the array | ||
* @param {Number} count Number of vec2s to iterate over. If 0 iterates over entire array | ||
* @param {Function} fn Function to call for each vector in the array | ||
* @param {Object} [arg] additional argument to pass to fn | ||
* @returns {Array} a | ||
* @function | ||
*/ | ||
var forEach$2 = function () { | ||
var vec = create$8(); | ||
return function (a, stride, offset, count, fn, arg) { | ||
var i = void 0, | ||
l = void 0; | ||
if (!stride) { | ||
stride = 2; | ||
} | ||
if (!offset) { | ||
offset = 0; | ||
} | ||
if (count) { | ||
l = Math.min(count * stride + offset, a.length); | ||
} else { | ||
l = a.length; | ||
} | ||
for (i = offset; i < l; i += stride) { | ||
vec[0] = a[i];vec[1] = a[i + 1]; | ||
fn(vec, vec, arg); | ||
a[i] = vec[0];a[i + 1] = vec[1]; | ||
} | ||
return a; | ||
}; | ||
}(); | ||
const TWOPI = 2 * Math.PI; | ||
const Links = [['0.1'], ['3.1', [3042, 47]], ['4.1', [1375, 69]], ['5.1', [7357, 69]], ['5.2', | ||
[1849, 81]], ['6.1', [1534, 96]], ['6.2', [0, 82]], ['6.3', [10652, 85]], ['7.1', [7845, | ||
94]], ['7.2', [5595, 86]], ['7.3', [190, 122]], ['7.4', [3640, 102]], ['7.5', [1751, | ||
98]], ['7.6', [5020, 102]], ['7.7', [9660, 91]], ['8.1', [1279, 96]], ['8.2', [9751, | ||
108]], ['8.3', [2817, 112]], ['8.4', [3938, 105]], ['8.5', [4043, 105]], ['8.6', [4623, | ||
90]], ['8.7', [1191, 88]], ['8.8', [5681, 100]], ['8.9', [1930, 98]], ['8.10', [9031, | ||
85]], ['8.11', [1444, 90]], ['8.12', [4828, 94]], ['8.13', [6231, 90]], ['8.14', [885, | ||
98]], ['8.15', [9574, 86]], ['8.16', [4148, 85]], ['8.17', [312, 81]], ['8.18', [2243, | ||
97]], ['8.19', [6321, 86]], ['8.20', [7529, 88]], ['8.21', [686, 89]], ['9.1', [7013, | ||
102]], ['9.2', [10544, 108]], ['9.3', [4922, 98]], ['9.4', [3322, 89]], ['9.5', [3411, | ||
114]], ['9.6', [8182, 98]], ['9.7', [592, 94]], ['9.8', [10353, 91]], ['9.9', [2140, | ||
103]], ['9.10', [8392, 112]], ['9.11', [9349, 120]], ['9.12', [2929, 113]], ['9.13', | ||
[9116, 123]], ['9.14', [3089, 102]], ['9.15', [7939, 116]], ['9.16', [5462, 133]], | ||
['9.17', [10242, 111]], ['9.18', [82, 108]], ['9.19', [5122, 118]], ['9.20', [7725, | ||
120]], ['9.21', [486, 106]], ['9.22', [1630, 121]], ['9.23', [2436, 113]], ['9.24', | ||
[775, 110]], ['9.25', [6601, 102]], ['9.26', [3525, 115]], ['9.27', [6407, 89]], | ||
['9.28', [7426, 103]], ['9.29', [8280, 112]], ['9.30', [5781, 111]], ['9.31', [6703, | ||
120]], ['9.32', [8055, 127]], ['9.33', [7227, 130]], ['9.34', [4713, 115]], ['9.35', | ||
[3191, 131]], ['9.36', [5240, 119]], ['0.2.1'], ['2.2.1', [2648, 36], [2684, 36]], | ||
['4.2.1', [10161, 39], [10200, 42]], ['5.2.1', [8728, 38], [8766, 39]], ['6.2.1', [8931, | ||
49], [8980, 51]], ['6.2.2', [2340, 47], [2387, 49]], ['6.2.3', [3742, 41], [3783, 54]], | ||
['7.2.1', [9859, 44], [9903, 55]], ['7.2.2', [393, 45], [438, 48]], ['7.2.3', [6928, | ||
39], [6967, 46]], ['7.2.4', [6496, 77], [6573, 28]], ['7.2.5', [5892, 45], [5937, 68]], | ||
['7.2.6', [6823, 27], [6850, 78]], ['7.2.7', [10057, 78], [10135, 26]], ['7.2.8', [9239, | ||
43], [9282, 67]], ['8.2.1', [7115, 58], [7173, 54]], ['8.2.2', [6005, 53], [6058, 59]], | ||
['8.2.3', [8504, 42], [8546, 63]], ['8.2.4', [4357, 50], [4407, 57]], ['8.2.5', [9958, | ||
51], [10009, 48]], ['8.2.6', [10444, 46], [10490, 54]], ['8.2.7', [5359, 47], [5406, | ||
56]], ['8.2.8', [1097, 50], [1147, 44]], ['8.2.9', [2028, 42], [2070, 70]], ['8.2.10', | ||
[4233, 96], [4329, 28]], ['8.2.11', [6117, 93], [6210, 21]], ['0.3.1'], ['6.3.1', [3837, | ||
37], [3874, 31], [3905, 33]], ['6.3.2', [9469, 38], [9507, 34], [9541, 33]], ['6.3.3', | ||
[2720, 35], [2755, 30], [2785, 32]], ['7.3.1', [7617, 44], [7661, 33], [7694, 31]], | ||
['8.3.1', [8805, 45], [8850, 49], [8899, 32]], ['8.3.2', [8609, 45], [8654, 48], [8702, | ||
26]], ['8.3.3', [983, 43], [1026, 36], [1062, 35]], ['8.3.4', [4464, 28], [4492, 29], | ||
[4521, 102]], ['8.3.5', [2549, 26], [2575, 29], [2604, 44]]]; | ||
function perp(u, dest) { | ||
const v = [1, 0, 0]; | ||
cross(dest, u, v); | ||
const e = dot(dest, dest); | ||
if (e < 0.01) { | ||
copy$4(v, [0, 1, 0]); | ||
cross(dest, u, v); | ||
} | ||
return normalize(dest, dest); | ||
} | ||
function direction(vec, vec2$$1, dest) { | ||
if (!dest) { dest = vec; } | ||
let x = vec[0] - vec2$$1[0], | ||
y = vec[1] - vec2$$1[1], | ||
z = vec[2] - vec2$$1[2], | ||
len$$1 = Math.sqrt(x * x + y * y + z * z); | ||
if (!len$$1) { | ||
dest[0] = 0; | ||
dest[1] = 0; | ||
dest[2] = 0; | ||
return dest; | ||
} | ||
len$$1 = 1 / len$$1; | ||
dest[0] = x * len$$1; | ||
dest[1] = y * len$$1; | ||
dest[2] = z * len$$1; | ||
return dest; | ||
} | ||
function clamp(v,least,most) {return Math.max(Math.min(most,v),least)} | ||
function packSnorm16(value) {return Math.round(clamp(value,-1,1)*32767)} | ||
function vec4_packSnorm16(out,src) { | ||
out[0]=packSnorm16(src[0]); | ||
out[1]=packSnorm16(src[1]); | ||
out[2]=packSnorm16(src[2]); | ||
out[3]=packSnorm16(src[3]); | ||
return out | ||
} | ||
class Knotess { | ||
constructor(centerlines) { | ||
console.assert(ArrayBuffer.prototype.constructor === centerlines.constructor); | ||
this.spines = new Float32Array(centerlines); | ||
this.Rolfsen = [ | ||
'0.1 3.1 4.1 5.1 5.2 6.1 6.2 6.3 7.1', | ||
'7.2 7.3 7.4 7.5 7.6 7.7 8.1 8.2 8.3', | ||
'8.4 8.5 8.6 8.7 8.8 8.9 8.10 8.11 8.12', | ||
'8.13 8.14 8.15 8.16 8.17 8.18 8.19 8.20 8.21', | ||
'9.1 9.2 9.3 9.4 9.5 9.6 9.7 9.8 9.9', | ||
'9.10 9.11 9.12 9.13 9.14 9.15 9.16 9.17 9.18', | ||
'9.19 9.20 9.21 9.22 9.23 9.24 9.25 9.26 9.27', | ||
'9.28 9.29 9.30 9.31 9.32 9.33 9.34 9.35 9.36', | ||
'0.2.1 2.2.1 4.2.1 5.2.1 6.2.1 6.2.2 6.2.3 7.2.1 7.2.2', | ||
'7.2.3 7.2.4 7.2.5 7.2.6 7.2.7 7.2.8 8.2.1 8.2.2 8.2.3', | ||
'8.2.4 8.2.5 8.2.6 8.2.7 8.2.8 8.2.9 8.2.10 8.2.11 0.3.1', | ||
'6.3.1 6.3.2 6.3.3 7.3.1 8.3.1 8.3.2 8.3.3 8.3.4 8.3.5' | ||
]; | ||
this.LinearRolfsen = []; | ||
this.LinearRolfsenLookup = {}; | ||
for (const row of this.Rolfsen) { | ||
for (const id of row.split(' ')) { | ||
this.LinearRolfsenLookup[id] = this.LinearRolfsen.length; | ||
this.LinearRolfsen.push(id); | ||
} | ||
} | ||
this.LinksDb = {}; | ||
for (const link of Links) { | ||
this.LinksDb[link[0]] = link.slice(1); | ||
} | ||
} | ||
getPreviousLinkId(linkid) { | ||
const index = this.LinearRolfsenLookup[linkid]; | ||
return this.LinearRolfsen[Math.max(0, index - 1)]; | ||
} | ||
getNextLinkId(linkid) { | ||
const index = this.LinearRolfsenLookup[linkid]; | ||
const upper = this.LinearRolfsen.length - 1; | ||
return this.LinearRolfsen[Math.min(upper, index + 1)]; | ||
} | ||
// Given an Alexander-Briggs-Rolfsen identifier and an optional configuration dictionary, | ||
// returns an array of 'meshes' where each mesh is a dictionary with three entries: a | ||
// `Float32Array` vertex buffer, a `Uint16Array` triangle buffer, and (optionally) a | ||
// `Uint16Array` wireframe buffer. The vertex buffer is a flat array of PX PY PZ NX NY NZ. | ||
tessellate(linkid, options) { | ||
const defaults = { | ||
scale: 0.15, | ||
bézierSlices: 5, | ||
polygonSides: 10, | ||
radius: 0.07, | ||
wireframe: false, | ||
tangents: false, | ||
tangentSmoothness: 3 | ||
}; | ||
options = Object.assign(defaults, options); | ||
const ranges = this.LinksDb[linkid]; | ||
if (ranges.length) { | ||
return this.tessellateLink(ranges, options); | ||
} | ||
if (linkid == "0.1") { | ||
const mesh = this.tessellate("2.2.1", options)[0]; | ||
return [this.clone(mesh, [0.5, -0.25, 0])]; | ||
} | ||
if (linkid == "0.2.1") { | ||
const mesh = this.tessellate("2.2.1", options)[0]; | ||
return [ | ||
this.clone(mesh, [0, 0, 0]), | ||
this.clone(mesh, [0.5, 0, 0])]; | ||
} | ||
if (linkid == "0.3.1") { | ||
const mesh = this.tessellate("2.2.1", options)[0]; | ||
return [ | ||
this.clone(mesh, [0, 0, 0]), | ||
this.clone(mesh, [0.5, 0, 0]), | ||
this.clone(mesh, [1.0, 0, 0])]; | ||
} | ||
return []; | ||
} | ||
clone(mesh, translation) { | ||
const result = { | ||
vertices: new Float32Array(mesh.vertices), | ||
triangles: mesh.triangles, | ||
}; | ||
if (mesh.tangents) { | ||
result.tangents = new Uint16Array(mesh.tangents); | ||
} | ||
if (mesh.wireframe) { | ||
result.wireframe = new Uint16Array(mesh.wireframe); | ||
} | ||
const nverts = mesh.vertices.length / 6; | ||
for (let i = 0; i < nverts; i++) { | ||
result.vertices[i * 6 + 0] += translation[0]; | ||
result.vertices[i * 6 + 1] += translation[1]; | ||
result.vertices[i * 6 + 2] += translation[2]; | ||
} | ||
return result; | ||
} | ||
// Consumes an array of RANGE where RANGE = [INTEGER, INTEGER] | ||
// Produces an array of MESH where MESH = {vertices: Float32Array, triangles: Uint16Array} | ||
tessellateLink(ranges, options) { | ||
return ranges.map((range) => this.tessellateComponent(range, options)); | ||
} | ||
// Consumes [INTEGER, INTEGER] | ||
// Produces {vertices: Float32Array, triangles: Uint16Array} | ||
tessellateComponent(component, options) { | ||
let centerline, faceCount, i, j, lineCount, next, polygonCount; | ||
let polygonEdge, ptr, rawBuffer, segmentData, sides, sweepEdge, tri, triangles, tube, v; | ||
let wireframe = null; | ||
// Perform Bézier interpolation | ||
segmentData = this.spines.subarray(component[0] * 3, component[0] * 3 + component[1] * 3); | ||
centerline = this.getKnotPath(segmentData, options); | ||
// Create a positions buffer for a swept octagon | ||
rawBuffer = this.generateTube(centerline, options); | ||
tube = rawBuffer; | ||
// Create the index buffer for the tube wireframe | ||
polygonCount = centerline.length / 3 - 1; | ||
sides = options.polygonSides; | ||
lineCount = polygonCount * sides * 2; | ||
if (options.wireframe) { | ||
rawBuffer = new Uint16Array(lineCount * 2); | ||
[i, ptr] = [0, 0]; | ||
while (i < polygonCount * (sides + 1)) { | ||
j = 0; | ||
while (j < sides) { | ||
sweepEdge = rawBuffer.subarray(ptr + 2, ptr + 4); | ||
sweepEdge[0] = i + j; | ||
sweepEdge[1] = i + j + sides + 1; | ||
[ptr, j] = [ptr + 2, j + 1]; | ||
} | ||
i += sides + 1; | ||
} | ||
i = 0; | ||
while (i < polygonCount * (sides + 1)) { | ||
j = 0; | ||
while (j < sides) { | ||
polygonEdge = rawBuffer.subarray(ptr + 0, ptr + 2); | ||
polygonEdge[0] = i + j; | ||
polygonEdge[1] = i + j + 1; | ||
[ptr, j] = [ptr + 2, j + 1]; | ||
} | ||
i += sides + 1; | ||
} | ||
wireframe = rawBuffer; | ||
} | ||
// Create the index buffer for the solid tube | ||
faceCount = centerline.length / 3 * sides * 2; | ||
rawBuffer = new Uint16Array(faceCount * 3); | ||
[i, ptr, v] = [0, 0, 0]; | ||
while (++i < centerline.length / 3) { | ||
j = -1; | ||
while (++j < sides) { | ||
next = (j + 1) % sides; | ||
tri = rawBuffer.subarray(ptr + 0, ptr + 3); | ||
tri[0] = v + next + sides + 1; | ||
tri[1] = v + next; | ||
tri[2] = v + j; | ||
tri = rawBuffer.subarray(ptr + 3, ptr + 6); | ||
tri[0] = v + j; | ||
tri[1] = v + j + sides + 1; | ||
tri[2] = v + next + sides + 1; | ||
ptr += 6; | ||
} | ||
v += sides + 1; | ||
} | ||
triangles = rawBuffer; | ||
// Generate surface orientation quaternions. | ||
let tangents = null; | ||
if (options.tangents) { | ||
const nverts = tube.length / 6; | ||
tangents = new Uint16Array(4 * nverts); | ||
for (let i = 0; i < nverts; ++i) { | ||
const n = tube.subarray(i * 6 + 3, i * 6 + 6); | ||
const dst = tangents.subarray(i * 4, i * 4 + 4); | ||
const b = cross(create$4(), n, [1, 0, 0]); | ||
const t = cross(create$4(), b, n); | ||
const q = fromMat3([0, 0, 0, 1], [ | ||
t[0], t[1], t[2], | ||
b[0], b[1], b[2], | ||
n[0], n[1], n[2]]); | ||
vec4_packSnorm16(dst, q); | ||
} | ||
} | ||
return { | ||
vertices: tube, | ||
tangents: tangents, | ||
triangles: triangles, | ||
wireframe: wireframe | ||
}; | ||
} | ||
// Evaluate a Bézier function for smooth interpolation. | ||
// Return a Float32Array | ||
getKnotPath(data, options) { | ||
let a, b, c, dt, i, ii, j, k, l, n, p, r, rawBuffer, ref, slices, t, tt, v, v1, v2, v3, v4; | ||
let slice; | ||
slices = options.bézierSlices; | ||
rawBuffer = new Float32Array(data.length * slices + 3); | ||
[i, j] = [0, 0]; | ||
while (i < data.length + 3) { | ||
r = (function() { | ||
let k, len$$1, ref, results; | ||
ref = [0, 2, 3, 5, 6, 8]; | ||
results = []; | ||
for (k = 0, len$$1 = ref.length; k < len$$1; k++) { | ||
n = ref[k]; | ||
results.push((i + n) % data.length); | ||
} | ||
return results; | ||
})(); | ||
a = data.subarray(r[0], r[1] + 1); | ||
b = data.subarray(r[2], r[3] + 1); | ||
c = data.subarray(r[4], r[5] + 1); | ||
v1 = clone$4(a); | ||
v4 = clone$4(b); | ||
lerp(v1, v1, b, 0.5); | ||
lerp(v4, v4, c, 0.5); | ||
v2 = clone$4(v1); | ||
v3 = clone$4(v4); | ||
lerp(v2, v2, b, 1 / 3); | ||
lerp(v3, v3, b, 1 / 3); | ||
t = dt = 1 / (slices + 1); | ||
for (slice = k = 0, ref = slices; (0 <= ref ? k < ref : k > ref); | ||
slice = 0 <= ref ? ++k : --k) { | ||
tt = 1 - t; | ||
c = [tt * tt * tt, 3 * tt * tt * t, 3 * tt * t * t, t * t * t]; | ||
p = (function() { | ||
let l, len$$1, ref1, results; | ||
ref1 = [v1, v2, v3, v4]; | ||
results = []; | ||
for (l = 0, len$$1 = ref1.length; l < len$$1; l++) { | ||
v = ref1[l]; | ||
results.push(clone$4(v)); | ||
} | ||
return results; | ||
})(); | ||
for (ii = l = 0; l < 4; ii = ++l) { | ||
scale$4(p[ii], p[ii], c[ii]); | ||
} | ||
p = p.reduce(function(a, b) { | ||
return add$4(a, a, b); | ||
}); | ||
scale$4(p, p, options.scale); | ||
rawBuffer.set(p, j); | ||
j += 3; | ||
if (j >= rawBuffer.length) { | ||
return rawBuffer; | ||
} | ||
t += dt; | ||
} | ||
i += 3; | ||
} | ||
} | ||
// Sweep a n-sided polygon along the given centerline. | ||
// Returns the mesh verts as a Float32Arrays. | ||
// Repeats the vertex along the seam to allow nice texture coords. | ||
generateTube(centerline, options) { | ||
let B, C, basis, center, count, dtheta, frames, i, m, mesh, n, normal, p, r, theta; | ||
let v, x, y, z; | ||
n = options.polygonSides; | ||
dtheta = TWOPI / n; | ||
frames = this.generateFrames(centerline, options); | ||
count = centerline.length / 3; | ||
mesh = new Float32Array(count * (n + 1) * 6); | ||
[i, m] = [0, 0]; | ||
p = create$4(); | ||
r = options.radius; | ||
while (i < count) { | ||
v = 0; | ||
basis = (function() { | ||
let k, results; | ||
results = []; | ||
for (C = k = 0; k <= 2; C = ++k) { | ||
results.push(frames[C].subarray(i * 3, i * 3 + 3)); | ||
} | ||
return results; | ||
})(); | ||
basis = (function() { | ||
let k, len$$1, results; | ||
results = []; | ||
for (k = 0, len$$1 = basis.length; k < len$$1; k++) { | ||
B = basis[k]; | ||
results.push((function() { | ||
let l, results1; | ||
results1 = []; | ||
for (C = l = 0; l <= 2; C = ++l) { | ||
results1.push(B[C]); | ||
} | ||
return results1; | ||
})()); | ||
} | ||
return results; | ||
})(); | ||
basis = basis.reduce(function(A, B) { | ||
return A.concat(B); | ||
}); | ||
theta = 0; | ||
while (v < n + 1) { | ||
x = r * Math.cos(theta); | ||
y = r * Math.sin(theta); | ||
z = 0; | ||
transformMat3(p, [x, y, z], basis); | ||
p[0] += centerline[i * 3 + 0]; | ||
p[1] += centerline[i * 3 + 1]; | ||
p[2] += centerline[i * 3 + 2]; | ||
// Stamp p into 'm', skipping over the normal: | ||
mesh.set(p, m); | ||
[m, v, theta] = [m + 6, v + 1, theta + dtheta]; | ||
} | ||
i++; | ||
} | ||
// Next, populate normals: | ||
[i, m] = [0, 0]; | ||
normal = create$4(); | ||
center = create$4(); | ||
while (i < count) { | ||
v = 0; | ||
while (v < n + 1) { | ||
p[0] = mesh[m + 0]; | ||
p[1] = mesh[m + 1]; | ||
p[2] = mesh[m + 2]; | ||
center[0] = centerline[i * 3 + 0]; | ||
center[1] = centerline[i * 3 + 1]; | ||
center[2] = centerline[i * 3 + 2]; | ||
direction(p, center, normal); | ||
// Stamp n into 'm', skipping over the position: | ||
mesh.set(normal, m + 3); | ||
[m, v] = [m + 6, v + 1]; | ||
} | ||
i++; | ||
} | ||
return mesh; | ||
} | ||
// Generate reasonable orthonormal basis vectors for curve in R3. | ||
// Returns three lists-of-vec3's for the basis vectors. | ||
// See 'Computation of Rotation Minimizing Frame' by Wang and Jüttler. | ||
generateFrames(centerline, options) { | ||
let count, frameR, frameS, frameT, i, j, n, r0, ri, rj, s0, si, sj, t0, ti, tj, xi, xj; | ||
count = centerline.length / 3; | ||
frameR = new Float32Array(count * 3); | ||
frameS = new Float32Array(count * 3); | ||
frameT = new Float32Array(count * 3); | ||
// Obtain unit-length tangent vectors | ||
i = -1; | ||
while (++i < count) { | ||
j = (i + 1 + options.tangentSmoothness) % (count - 1); | ||
xi = centerline.subarray(i * 3, i * 3 + 3); | ||
xj = centerline.subarray(j * 3, j * 3 + 3); | ||
ti = frameT.subarray(i * 3, i * 3 + 3); | ||
direction(xi, xj, ti); | ||
} | ||
// Allocate some temporaries for vector math | ||
[r0, s0, t0] = (function() { | ||
let k, results; | ||
results = []; | ||
for (n = k = 0; k <= 2; n = ++k) { | ||
results.push(create$4()); | ||
} | ||
return results; | ||
})(); | ||
[rj, sj, tj] = (function() { | ||
let k, results; | ||
results = []; | ||
for (n = k = 0; k <= 2; n = ++k) { | ||
results.push(create$4()); | ||
} | ||
return results; | ||
})(); | ||
// Create a somewhat-arbitrary initial frame (r0, s0, t0) | ||
copy$4(t0, frameT.subarray(0, 3)); | ||
perp(t0, r0); | ||
cross(s0, t0, r0); | ||
normalize(r0, r0); | ||
normalize(s0, s0); | ||
copy$4(frameR.subarray(0, 3), r0); | ||
copy$4(frameS.subarray(0, 3), s0); | ||
// Use parallel transport to sweep the frame | ||
// TODO: add minor twist so that a swept triangle aligns without cracks. | ||
[i, j] = [0, 1]; | ||
[ri, si, ti] = [r0, s0, t0]; | ||
while (i < count - 1) { | ||
j = i + 1; | ||
xi = centerline.subarray(i * 3, i * 3 + 3); | ||
xj = centerline.subarray(j * 3, j * 3 + 3); | ||
ti = frameT.subarray(i * 3, i * 3 + 3); | ||
tj = frameT.subarray(j * 3, j * 3 + 3); | ||
cross(sj, tj, ri); | ||
normalize(sj, sj); | ||
cross(rj, sj, tj); | ||
copy$4(frameR.subarray(j * 3, j * 3 + 3), rj); | ||
copy$4(frameS.subarray(j * 3, j * 3 + 3), sj); | ||
copy$4(ri, rj); | ||
++i; | ||
} | ||
// Return the basis columns | ||
return [frameR, frameS, frameT]; | ||
} | ||
} | ||
return Knotess; | ||
}))); | ||
!function(r,t){"object"==typeof exports&&"undefined"!=typeof module?module.exports=t():"function"==typeof define&&define.amd?define(t):r.Knotess=t()}(this,function(){"use strict";var r=1e-6,t="undefined"!=typeof Float32Array?Float32Array:Array;Math.PI;function n(){var r=new t(3);return t!=Float32Array&&(r[0]=0,r[1]=0,r[2]=0),r}function e(r){var n=new t(3);return n[0]=r[0],n[1]=r[1],n[2]=r[2],n}function s(r,n,e){var s=new t(3);return s[0]=r,s[1]=n,s[2]=e,s}function a(r,t){return r[0]=t[0],r[1]=t[1],r[2]=t[2],r}function o(r,t,n){return r[0]=t[0]+n[0],r[1]=t[1]+n[1],r[2]=t[2]+n[2],r}function i(r,t,n){return r[0]=t[0]*n,r[1]=t[1]*n,r[2]=t[2]*n,r}function u(r,t){var n=t[0],e=t[1],s=t[2],a=n*n+e*e+s*s;return a>0&&(a=1/Math.sqrt(a),r[0]=t[0]*a,r[1]=t[1]*a,r[2]=t[2]*a),r}function l(r,t){return r[0]*t[0]+r[1]*t[1]+r[2]*t[2]}function f(r,t,n){var e=t[0],s=t[1],a=t[2],o=n[0],i=n[1],u=n[2];return r[0]=s*u-a*i,r[1]=a*o-e*u,r[2]=e*i-s*o,r}function c(r,t,n,e){var s=t[0],a=t[1],o=t[2];return r[0]=s+e*(n[0]-s),r[1]=a+e*(n[1]-a),r[2]=o+e*(n[2]-o),r}function h(r,t,n){var e=t[0],s=t[1],a=t[2];return r[0]=e*n[0]+s*n[3]+a*n[6],r[1]=e*n[1]+s*n[4]+a*n[7],r[2]=e*n[2]+s*n[5]+a*n[8],r}var y,g=function(r){var t=r[0],n=r[1],e=r[2];return Math.sqrt(t*t+n*n+e*e)};y=n();!function(){var r,n=(r=new t(4),t!=Float32Array&&(r[0]=0,r[1]=0,r[2]=0,r[3]=0),r)}();function v(){var r=new t(4);return t!=Float32Array&&(r[0]=0,r[1]=0,r[2]=0),r[3]=1,r}function b(t,n,e,s){var a=n[0],o=n[1],i=n[2],u=n[3],l=e[0],f=e[1],c=e[2],h=e[3],y=void 0,g=void 0,v=void 0,b=void 0,p=void 0;return(g=a*l+o*f+i*c+u*h)<0&&(g=-g,l=-l,f=-f,c=-c,h=-h),1-g>r?(y=Math.acos(g),v=Math.sin(y),b=Math.sin((1-s)*y)/v,p=Math.sin(s*y)/v):(b=1-s,p=s),t[0]=b*a+p*l,t[1]=b*o+p*f,t[2]=b*i+p*c,t[3]=b*u+p*h,t}function p(r,t){var n=t[0]+t[4]+t[8],e=void 0;if(n>0)e=Math.sqrt(n+1),r[3]=.5*e,e=.5/e,r[0]=(t[5]-t[7])*e,r[1]=(t[6]-t[2])*e,r[2]=(t[1]-t[3])*e;else{var s=0;t[4]>t[0]&&(s=1),t[8]>t[3*s+s]&&(s=2);var a=(s+1)%3,o=(s+2)%3;e=Math.sqrt(t[3*s+s]-t[3*a+a]-t[3*o+o]+1),r[s]=.5*e,e=.5/e,r[3]=(t[3*a+o]-t[3*o+a])*e,r[a]=(t[3*a+s]+t[3*s+a])*e,r[o]=(t[3*o+s]+t[3*s+o])*e}return r}var d,w,A,L,m,M,F,R=function(r,t){var n=t[0],e=t[1],s=t[2],a=t[3],o=n*n+e*e+s*s+a*a;return o>0&&(o=1/Math.sqrt(o),r[0]=n*o,r[1]=e*o,r[2]=s*o,r[3]=a*o),r};d=n(),w=s(1,0,0),A=s(0,1,0),L=v(),m=v(),M=new t(9),t!=Float32Array&&(M[1]=0,M[2]=0,M[3]=0,M[5]=0,M[6]=0,M[7]=0),M[0]=1,M[4]=1,M[8]=1,F=M;!function(){var r,n=(r=new t(2),t!=Float32Array&&(r[0]=0,r[1]=0),r)}();const k=2*Math.PI,S=[["0.1"],["3.1",[3042,47]],["4.1",[1375,69]],["5.1",[7357,69]],["5.2",[1849,81]],["6.1",[1534,96]],["6.2",[0,82]],["6.3",[10652,85]],["7.1",[7845,94]],["7.2",[5595,86]],["7.3",[190,122]],["7.4",[3640,102]],["7.5",[1751,98]],["7.6",[5020,102]],["7.7",[9660,91]],["8.1",[1279,96]],["8.2",[9751,108]],["8.3",[2817,112]],["8.4",[3938,105]],["8.5",[4043,105]],["8.6",[4623,90]],["8.7",[1191,88]],["8.8",[5681,100]],["8.9",[1930,98]],["8.10",[9031,85]],["8.11",[1444,90]],["8.12",[4828,94]],["8.13",[6231,90]],["8.14",[885,98]],["8.15",[9574,86]],["8.16",[4148,85]],["8.17",[312,81]],["8.18",[2243,97]],["8.19",[6321,86]],["8.20",[7529,88]],["8.21",[686,89]],["9.1",[7013,102]],["9.2",[10544,108]],["9.3",[4922,98]],["9.4",[3322,89]],["9.5",[3411,114]],["9.6",[8182,98]],["9.7",[592,94]],["9.8",[10353,91]],["9.9",[2140,103]],["9.10",[8392,112]],["9.11",[9349,120]],["9.12",[2929,113]],["9.13",[9116,123]],["9.14",[3089,102]],["9.15",[7939,116]],["9.16",[5462,133]],["9.17",[10242,111]],["9.18",[82,108]],["9.19",[5122,118]],["9.20",[7725,120]],["9.21",[486,106]],["9.22",[1630,121]],["9.23",[2436,113]],["9.24",[775,110]],["9.25",[6601,102]],["9.26",[3525,115]],["9.27",[6407,89]],["9.28",[7426,103]],["9.29",[8280,112]],["9.30",[5781,111]],["9.31",[6703,120]],["9.32",[8055,127]],["9.33",[7227,130]],["9.34",[4713,115]],["9.35",[3191,131]],["9.36",[5240,119]],["0.2.1"],["2.2.1",[2648,36],[2684,36]],["4.2.1",[10161,39],[10200,42]],["5.2.1",[8728,38],[8766,39]],["6.2.1",[8931,49],[8980,51]],["6.2.2",[2340,47],[2387,49]],["6.2.3",[3742,41],[3783,54]],["7.2.1",[9859,44],[9903,55]],["7.2.2",[393,45],[438,48]],["7.2.3",[6928,39],[6967,46]],["7.2.4",[6496,77],[6573,28]],["7.2.5",[5892,45],[5937,68]],["7.2.6",[6823,27],[6850,78]],["7.2.7",[10057,78],[10135,26]],["7.2.8",[9239,43],[9282,67]],["8.2.1",[7115,58],[7173,54]],["8.2.2",[6005,53],[6058,59]],["8.2.3",[8504,42],[8546,63]],["8.2.4",[4357,50],[4407,57]],["8.2.5",[9958,51],[10009,48]],["8.2.6",[10444,46],[10490,54]],["8.2.7",[5359,47],[5406,56]],["8.2.8",[1097,50],[1147,44]],["8.2.9",[2028,42],[2070,70]],["8.2.10",[4233,96],[4329,28]],["8.2.11",[6117,93],[6210,21]],["0.3.1"],["6.3.1",[3837,37],[3874,31],[3905,33]],["6.3.2",[9469,38],[9507,34],[9541,33]],["6.3.3",[2720,35],[2755,30],[2785,32]],["7.3.1",[7617,44],[7661,33],[7694,31]],["8.3.1",[8805,45],[8850,49],[8899,32]],["8.3.2",[8609,45],[8654,48],[8702,26]],["8.3.3",[983,43],[1026,36],[1062,35]],["8.3.4",[4464,28],[4492,29],[4521,102]],["8.3.5",[2549,26],[2575,29],[2604,44]]];function q(r,t,n){n||(n=r);let e=r[0]-t[0],s=r[1]-t[1],a=r[2]-t[2],o=Math.sqrt(e*e+s*s+a*a);return o?(o=1/o,n[0]=e*o,n[1]=s*o,n[2]=a*o,n):(n[0]=0,n[1]=0,n[2]=0,n)}function x(r){return Math.round(32767*(t=r,n=-1,e=1,Math.max(Math.min(e,t),n)));var t,n,e}return class{constructor(r){console.assert(ArrayBuffer.prototype.constructor===r.constructor),this.spines=new Float32Array(r),this.Rolfsen=["0.1 3.1 4.1 5.1 5.2 6.1 6.2 6.3 7.1","7.2 7.3 7.4 7.5 7.6 7.7 8.1 8.2 8.3","8.4 8.5 8.6 8.7 8.8 8.9 8.10 8.11 8.12","8.13 8.14 8.15 8.16 8.17 8.18 8.19 8.20 8.21","9.1 9.2 9.3 9.4 9.5 9.6 9.7 9.8 9.9","9.10 9.11 9.12 9.13 9.14 9.15 9.16 9.17 9.18","9.19 9.20 9.21 9.22 9.23 9.24 9.25 9.26 9.27","9.28 9.29 9.30 9.31 9.32 9.33 9.34 9.35 9.36","0.2.1 2.2.1 4.2.1 5.2.1 6.2.1 6.2.2 6.2.3 7.2.1 7.2.2","7.2.3 7.2.4 7.2.5 7.2.6 7.2.7 7.2.8 8.2.1 8.2.2 8.2.3","8.2.4 8.2.5 8.2.6 8.2.7 8.2.8 8.2.9 8.2.10 8.2.11 0.3.1","6.3.1 6.3.2 6.3.3 7.3.1 8.3.1 8.3.2 8.3.3 8.3.4 8.3.5"],this.LinearRolfsen=[],this.LinearRolfsenLookup={};for(const r of this.Rolfsen)for(const t of r.split(" "))this.LinearRolfsenLookup[t]=this.LinearRolfsen.length,this.LinearRolfsen.push(t);this.LinksDb={};for(const r of S)this.LinksDb[r[0]]=r.slice(1)}getPreviousLinkId(r){const t=this.LinearRolfsenLookup[r];return this.LinearRolfsen[Math.max(0,t-1)]}getNextLinkId(r){const t=this.LinearRolfsenLookup[r],n=this.LinearRolfsen.length-1;return this.LinearRolfsen[Math.min(n,t+1)]}tessellate(r,t){t=Object.assign({scale:.15,"bézierSlices":5,polygonSides:10,radius:.07,wireframe:!1,tangents:!1,tangentSmoothness:3},t);const n=this.LinksDb[r];if(n.length)return this.tessellateLink(n,t);if("0.1"==r){const r=this.tessellate("2.2.1",t)[0];return[this.clone(r,[.5,-.25,0])]}if("0.2.1"==r){const r=this.tessellate("2.2.1",t)[0];return[this.clone(r,[0,0,0]),this.clone(r,[.5,0,0])]}if("0.3.1"==r){const r=this.tessellate("2.2.1",t)[0];return[this.clone(r,[0,0,0]),this.clone(r,[.5,0,0]),this.clone(r,[1,0,0])]}return[]}clone(r,t){const n={vertices:new Float32Array(r.vertices),triangles:r.triangles};r.tangents&&(n.tangents=new Uint16Array(r.tangents)),r.wireframe&&(n.wireframe=new Uint16Array(r.wireframe));const e=r.vertices.length/6;for(let r=0;r<e;r++)n.vertices[6*r+0]+=t[0],n.vertices[6*r+1]+=t[1],n.vertices[6*r+2]+=t[2];return n}tessellateLink(r,t){return r.map(r=>this.tessellateComponent(r,t))}tessellateComponent(r,t){let e,s,a,o,i,u,l,c,h,y,g,v,b,d,w,A,L,m=null;if(g=this.spines.subarray(3*r[0],3*r[0]+3*r[1]),e=this.getKnotPath(g,t),A=y=this.generateTube(e,t),i=(l=e.length/3-1)*(v=t.polygonSides)*2,t.wireframe){for(y=new Uint16Array(2*i),[a,h]=[0,0];a<l*(v+1);){for(o=0;o<v;)(b=y.subarray(h+2,h+4))[0]=a+o,b[1]=a+o+v+1,[h,o]=[h+2,o+1];a+=v+1}for(a=0;a<l*(v+1);){for(o=0;o<v;)(c=y.subarray(h+0,h+2))[0]=a+o,c[1]=a+o+1,[h,o]=[h+2,o+1];a+=v+1}m=y}for(s=e.length/3*v*2,y=new Uint16Array(3*s),[a,h,L]=[0,0,0];++a<e.length/3;){for(o=-1;++o<v;)u=(o+1)%v,(d=y.subarray(h+0,h+3))[0]=L+u+v+1,d[1]=L+u,d[2]=L+o,(d=y.subarray(h+3,h+6))[0]=L+o,d[1]=L+o+v+1,d[2]=L+u+v+1,h+=6;L+=v+1}w=y;let M=null;if(t.tangents){const r=A.length/6;M=new Uint16Array(4*r);for(let t=0;t<r;++t){const r=A.subarray(6*t+3,6*t+6),e=M.subarray(4*t,4*t+4),s=f(n(),r,[1,0,0]),a=f(n(),s,r),o=p([0,0,0,1],[a[0],a[1],a[2],s[0],s[1],s[2],r[0],r[1],r[2]]);R=o,(F=e)[0]=x(R[0]),F[1]=x(R[1]),F[2]=x(R[2]),F[3]=x(R[3])}}var F,R;return{vertices:A,tangents:M,triangles:w,wireframe:m}}getKnotPath(r,t){let n,s,a,u,l,f,h,y,g,v,b,p,d,w,A,L,m,M,F,R,k,S,q;for(A=t.bézierSlices,d=new Float32Array(r.length*A+3),[l,h]=[0,0];l<r.length+3;){for(p=function(){let t,n,e,s;for(s=[],t=0,n=(e=[0,2,3,5,6,8]).length;t<n;t++)v=e[t],s.push((l+v)%r.length);return s}(),n=r.subarray(p[0],p[1]+1),s=r.subarray(p[2],p[3]+1),a=r.subarray(p[4],p[5]+1),F=e(n),S=e(s),c(F,F,s,.5),c(S,S,a,.5),R=e(F),k=e(S),c(R,R,s,1/3),c(k,k,s,1/3),L=u=1/(A+1),q=y=0,w=A;0<=w?y<w:y>w;q=0<=w?++y:--y){for(a=[(m=1-L)*m*m,3*m*m*L,3*m*L*L,L*L*L],b=function(){let r,t,n,s;for(s=[],r=0,t=(n=[F,R,k,S]).length;r<t;r++)M=n[r],s.push(e(M));return s}(),f=g=0;g<4;f=++g)i(b[f],b[f],a[f]);if(i(b=b.reduce(function(r,t){return o(r,r,t)}),b,t.scale),d.set(b,h),(h+=3)>=d.length)return d;L+=u}l+=3}}generateTube(r,t){let e,s,a,o,i,u,l,f,c,y,g,v,b,p,d,w,A,L,m;for(g=t.polygonSides,u=k/g,l=this.generateFrames(r,t),i=r.length/3,y=new Float32Array(i*(g+1)*6),[f,c]=[0,0],b=n(),p=t.radius;f<i;){for(w=0,a=function(){let r,t;for(t=[],s=r=0;r<=2;s=++r)t.push(l[s].subarray(3*f,3*f+3));return t}(),a=(a=function(){let r,t,n;for(n=[],r=0,t=a.length;r<t;r++)e=a[r],n.push(function(){let r,t;for(t=[],s=r=0;r<=2;s=++r)t.push(e[s]);return t}());return n}()).reduce(function(r,t){return r.concat(t)}),d=0;w<g+1;)m=0,h(b,[A=p*Math.cos(d),L=p*Math.sin(d),0],a),b[0]+=r[3*f+0],b[1]+=r[3*f+1],b[2]+=r[3*f+2],y.set(b,c),[c,w,d]=[c+6,w+1,d+u];f++}for([f,c]=[0,0],v=n(),o=n();f<i;){for(w=0;w<g+1;)b[0]=y[c+0],b[1]=y[c+1],b[2]=y[c+2],o[0]=r[3*f+0],o[1]=r[3*f+1],o[2]=r[3*f+2],q(b,o,v),y.set(v,c+3),[c,w]=[c+6,w+1];f++}return y}generateFrames(r,t){let e,s,o,i,c,h,y,g,v,b,p,d,w,A,L,m,M,F;for(e=r.length/3,s=new Float32Array(3*e),o=new Float32Array(3*e),i=new Float32Array(3*e),c=-1;++c<e;)h=(c+1+t.tangentSmoothness)%(e-1),q(M=r.subarray(3*c,3*c+3),F=r.subarray(3*h,3*h+3),L=i.subarray(3*c,3*c+3));for([g,p,A]=function(){let r,t;for(t=[],y=r=0;r<=2;y=++r)t.push(n());return t}(),[b,w,m]=function(){let r,t;for(t=[],y=r=0;r<=2;y=++r)t.push(n());return t}(),a(A,i.subarray(0,3)),function(r,t){const n=[1,0,0];f(t,r,n),l(t,t)<.01&&(a(n,[0,1,0]),f(t,r,n)),u(t,t)}(A,g),f(p,A,g),u(g,g),u(p,p),a(s.subarray(0,3),g),a(o.subarray(0,3),p),[c,h]=[0,1],[v,d,L]=[g,p,A];c<e-1;)h=c+1,M=r.subarray(3*c,3*c+3),F=r.subarray(3*h,3*h+3),L=i.subarray(3*c,3*c+3),f(w,m=i.subarray(3*h,3*h+3),v),u(w,w),f(b,w,m),a(s.subarray(3*h,3*h+3),b),a(o.subarray(3*h,3*h+3),w),a(v,b),++c;return[s,o,i]}}}); |
1174
knotess.min.js
@@ -1,1173 +0,1 @@ | ||
(function (global, factory) { | ||
typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() : | ||
typeof define === 'function' && define.amd ? define(factory) : | ||
(global.Knotess = factory()); | ||
}(this, (function () { 'use strict'; | ||
/** | ||
* Common utilities | ||
* @module glMatrix | ||
*/ | ||
// Configuration Constants | ||
var EPSILON = 0.000001; | ||
var ARRAY_TYPE = typeof Float32Array !== 'undefined' ? Float32Array : Array; | ||
var degree = Math.PI / 180; | ||
/** | ||
* 3x3 Matrix | ||
* @module mat3 | ||
*/ | ||
/** | ||
* Creates a new identity mat3 | ||
* | ||
* @returns {mat3} a new 3x3 matrix | ||
*/ | ||
function create$2() { | ||
var out = new ARRAY_TYPE(9); | ||
if (ARRAY_TYPE != Float32Array) { | ||
out[1] = 0; | ||
out[2] = 0; | ||
out[3] = 0; | ||
out[5] = 0; | ||
out[6] = 0; | ||
out[7] = 0; | ||
} | ||
out[0] = 1; | ||
out[4] = 1; | ||
out[8] = 1; | ||
return out; | ||
} | ||
/** | ||
* 3 Dimensional Vector | ||
* @module vec3 | ||
*/ | ||
/** | ||
* Creates a new, empty vec3 | ||
* | ||
* @returns {vec3} a new 3D vector | ||
*/ | ||
function create$4() { | ||
var out = new ARRAY_TYPE(3); | ||
if (ARRAY_TYPE != Float32Array) { | ||
out[0] = 0; | ||
out[1] = 0; | ||
out[2] = 0; | ||
} | ||
return out; | ||
} | ||
/** | ||
* Creates a new vec3 initialized with values from an existing vector | ||
* | ||
* @param {vec3} a vector to clone | ||
* @returns {vec3} a new 3D vector | ||
*/ | ||
function clone$4(a) { | ||
var out = new ARRAY_TYPE(3); | ||
out[0] = a[0]; | ||
out[1] = a[1]; | ||
out[2] = a[2]; | ||
return out; | ||
} | ||
/** | ||
* Calculates the length of a vec3 | ||
* | ||
* @param {vec3} a vector to calculate length of | ||
* @returns {Number} length of a | ||
*/ | ||
function length(a) { | ||
var x = a[0]; | ||
var y = a[1]; | ||
var z = a[2]; | ||
return Math.sqrt(x * x + y * y + z * z); | ||
} | ||
/** | ||
* Creates a new vec3 initialized with the given values | ||
* | ||
* @param {Number} x X component | ||
* @param {Number} y Y component | ||
* @param {Number} z Z component | ||
* @returns {vec3} a new 3D vector | ||
*/ | ||
function fromValues$4(x, y, z) { | ||
var out = new ARRAY_TYPE(3); | ||
out[0] = x; | ||
out[1] = y; | ||
out[2] = z; | ||
return out; | ||
} | ||
/** | ||
* Copy the values from one vec3 to another | ||
* | ||
* @param {vec3} out the receiving vector | ||
* @param {vec3} a the source vector | ||
* @returns {vec3} out | ||
*/ | ||
function copy$4(out, a) { | ||
out[0] = a[0]; | ||
out[1] = a[1]; | ||
out[2] = a[2]; | ||
return out; | ||
} | ||
/** | ||
* Adds two vec3's | ||
* | ||
* @param {vec3} out the receiving vector | ||
* @param {vec3} a the first operand | ||
* @param {vec3} b the second operand | ||
* @returns {vec3} out | ||
*/ | ||
function add$4(out, a, b) { | ||
out[0] = a[0] + b[0]; | ||
out[1] = a[1] + b[1]; | ||
out[2] = a[2] + b[2]; | ||
return out; | ||
} | ||
/** | ||
* Scales a vec3 by a scalar number | ||
* | ||
* @param {vec3} out the receiving vector | ||
* @param {vec3} a the vector to scale | ||
* @param {Number} b amount to scale the vector by | ||
* @returns {vec3} out | ||
*/ | ||
function scale$4(out, a, b) { | ||
out[0] = a[0] * b; | ||
out[1] = a[1] * b; | ||
out[2] = a[2] * b; | ||
return out; | ||
} | ||
/** | ||
* Normalize a vec3 | ||
* | ||
* @param {vec3} out the receiving vector | ||
* @param {vec3} a vector to normalize | ||
* @returns {vec3} out | ||
*/ | ||
function normalize(out, a) { | ||
var x = a[0]; | ||
var y = a[1]; | ||
var z = a[2]; | ||
var len = x * x + y * y + z * z; | ||
if (len > 0) { | ||
//TODO: evaluate use of glm_invsqrt here? | ||
len = 1 / Math.sqrt(len); | ||
out[0] = a[0] * len; | ||
out[1] = a[1] * len; | ||
out[2] = a[2] * len; | ||
} | ||
return out; | ||
} | ||
/** | ||
* Calculates the dot product of two vec3's | ||
* | ||
* @param {vec3} a the first operand | ||
* @param {vec3} b the second operand | ||
* @returns {Number} dot product of a and b | ||
*/ | ||
function dot(a, b) { | ||
return a[0] * b[0] + a[1] * b[1] + a[2] * b[2]; | ||
} | ||
/** | ||
* Computes the cross product of two vec3's | ||
* | ||
* @param {vec3} out the receiving vector | ||
* @param {vec3} a the first operand | ||
* @param {vec3} b the second operand | ||
* @returns {vec3} out | ||
*/ | ||
function cross(out, a, b) { | ||
var ax = a[0], | ||
ay = a[1], | ||
az = a[2]; | ||
var bx = b[0], | ||
by = b[1], | ||
bz = b[2]; | ||
out[0] = ay * bz - az * by; | ||
out[1] = az * bx - ax * bz; | ||
out[2] = ax * by - ay * bx; | ||
return out; | ||
} | ||
/** | ||
* Performs a linear interpolation between two vec3's | ||
* | ||
* @param {vec3} out the receiving vector | ||
* @param {vec3} a the first operand | ||
* @param {vec3} b the second operand | ||
* @param {Number} t interpolation amount, in the range [0-1], between the two inputs | ||
* @returns {vec3} out | ||
*/ | ||
function lerp(out, a, b, t) { | ||
var ax = a[0]; | ||
var ay = a[1]; | ||
var az = a[2]; | ||
out[0] = ax + t * (b[0] - ax); | ||
out[1] = ay + t * (b[1] - ay); | ||
out[2] = az + t * (b[2] - az); | ||
return out; | ||
} | ||
/** | ||
* Transforms the vec3 with a mat3. | ||
* | ||
* @param {vec3} out the receiving vector | ||
* @param {vec3} a the vector to transform | ||
* @param {mat3} m the 3x3 matrix to transform with | ||
* @returns {vec3} out | ||
*/ | ||
function transformMat3(out, a, m) { | ||
var x = a[0], | ||
y = a[1], | ||
z = a[2]; | ||
out[0] = x * m[0] + y * m[3] + z * m[6]; | ||
out[1] = x * m[1] + y * m[4] + z * m[7]; | ||
out[2] = x * m[2] + y * m[5] + z * m[8]; | ||
return out; | ||
} | ||
/** | ||
* Alias for {@link vec3.length} | ||
* @function | ||
*/ | ||
var len = length; | ||
/** | ||
* Perform some operation over an array of vec3s. | ||
* | ||
* @param {Array} a the array of vectors to iterate over | ||
* @param {Number} stride Number of elements between the start of each vec3. If 0 assumes tightly packed | ||
* @param {Number} offset Number of elements to skip at the beginning of the array | ||
* @param {Number} count Number of vec3s to iterate over. If 0 iterates over entire array | ||
* @param {Function} fn Function to call for each vector in the array | ||
* @param {Object} [arg] additional argument to pass to fn | ||
* @returns {Array} a | ||
* @function | ||
*/ | ||
var forEach = function () { | ||
var vec = create$4(); | ||
return function (a, stride, offset, count, fn, arg) { | ||
var i = void 0, | ||
l = void 0; | ||
if (!stride) { | ||
stride = 3; | ||
} | ||
if (!offset) { | ||
offset = 0; | ||
} | ||
if (count) { | ||
l = Math.min(count * stride + offset, a.length); | ||
} else { | ||
l = a.length; | ||
} | ||
for (i = offset; i < l; i += stride) { | ||
vec[0] = a[i];vec[1] = a[i + 1];vec[2] = a[i + 2]; | ||
fn(vec, vec, arg); | ||
a[i] = vec[0];a[i + 1] = vec[1];a[i + 2] = vec[2]; | ||
} | ||
return a; | ||
}; | ||
}(); | ||
/** | ||
* 4 Dimensional Vector | ||
* @module vec4 | ||
*/ | ||
/** | ||
* Creates a new, empty vec4 | ||
* | ||
* @returns {vec4} a new 4D vector | ||
*/ | ||
function create$5() { | ||
var out = new ARRAY_TYPE(4); | ||
if (ARRAY_TYPE != Float32Array) { | ||
out[0] = 0; | ||
out[1] = 0; | ||
out[2] = 0; | ||
out[3] = 0; | ||
} | ||
return out; | ||
} | ||
/** | ||
* Normalize a vec4 | ||
* | ||
* @param {vec4} out the receiving vector | ||
* @param {vec4} a vector to normalize | ||
* @returns {vec4} out | ||
*/ | ||
function normalize$1(out, a) { | ||
var x = a[0]; | ||
var y = a[1]; | ||
var z = a[2]; | ||
var w = a[3]; | ||
var len = x * x + y * y + z * z + w * w; | ||
if (len > 0) { | ||
len = 1 / Math.sqrt(len); | ||
out[0] = x * len; | ||
out[1] = y * len; | ||
out[2] = z * len; | ||
out[3] = w * len; | ||
} | ||
return out; | ||
} | ||
/** | ||
* Perform some operation over an array of vec4s. | ||
* | ||
* @param {Array} a the array of vectors to iterate over | ||
* @param {Number} stride Number of elements between the start of each vec4. If 0 assumes tightly packed | ||
* @param {Number} offset Number of elements to skip at the beginning of the array | ||
* @param {Number} count Number of vec4s to iterate over. If 0 iterates over entire array | ||
* @param {Function} fn Function to call for each vector in the array | ||
* @param {Object} [arg] additional argument to pass to fn | ||
* @returns {Array} a | ||
* @function | ||
*/ | ||
var forEach$1 = function () { | ||
var vec = create$5(); | ||
return function (a, stride, offset, count, fn, arg) { | ||
var i = void 0, | ||
l = void 0; | ||
if (!stride) { | ||
stride = 4; | ||
} | ||
if (!offset) { | ||
offset = 0; | ||
} | ||
if (count) { | ||
l = Math.min(count * stride + offset, a.length); | ||
} else { | ||
l = a.length; | ||
} | ||
for (i = offset; i < l; i += stride) { | ||
vec[0] = a[i];vec[1] = a[i + 1];vec[2] = a[i + 2];vec[3] = a[i + 3]; | ||
fn(vec, vec, arg); | ||
a[i] = vec[0];a[i + 1] = vec[1];a[i + 2] = vec[2];a[i + 3] = vec[3]; | ||
} | ||
return a; | ||
}; | ||
}(); | ||
/** | ||
* Quaternion | ||
* @module quat | ||
*/ | ||
/** | ||
* Creates a new identity quat | ||
* | ||
* @returns {quat} a new quaternion | ||
*/ | ||
function create$6() { | ||
var out = new ARRAY_TYPE(4); | ||
if (ARRAY_TYPE != Float32Array) { | ||
out[0] = 0; | ||
out[1] = 0; | ||
out[2] = 0; | ||
} | ||
out[3] = 1; | ||
return out; | ||
} | ||
/** | ||
* Sets a quat from the given angle and rotation axis, | ||
* then returns it. | ||
* | ||
* @param {quat} out the receiving quaternion | ||
* @param {vec3} axis the axis around which to rotate | ||
* @param {Number} rad the angle in radians | ||
* @returns {quat} out | ||
**/ | ||
function setAxisAngle(out, axis, rad) { | ||
rad = rad * 0.5; | ||
var s = Math.sin(rad); | ||
out[0] = s * axis[0]; | ||
out[1] = s * axis[1]; | ||
out[2] = s * axis[2]; | ||
out[3] = Math.cos(rad); | ||
return out; | ||
} | ||
/** | ||
* Performs a spherical linear interpolation between two quat | ||
* | ||
* @param {quat} out the receiving quaternion | ||
* @param {quat} a the first operand | ||
* @param {quat} b the second operand | ||
* @param {Number} t interpolation amount, in the range [0-1], between the two inputs | ||
* @returns {quat} out | ||
*/ | ||
function slerp(out, a, b, t) { | ||
// benchmarks: | ||
// http://jsperf.com/quaternion-slerp-implementations | ||
var ax = a[0], | ||
ay = a[1], | ||
az = a[2], | ||
aw = a[3]; | ||
var bx = b[0], | ||
by = b[1], | ||
bz = b[2], | ||
bw = b[3]; | ||
var omega = void 0, | ||
cosom = void 0, | ||
sinom = void 0, | ||
scale0 = void 0, | ||
scale1 = void 0; | ||
// calc cosine | ||
cosom = ax * bx + ay * by + az * bz + aw * bw; | ||
// adjust signs (if necessary) | ||
if (cosom < 0.0) { | ||
cosom = -cosom; | ||
bx = -bx; | ||
by = -by; | ||
bz = -bz; | ||
bw = -bw; | ||
} | ||
// calculate coefficients | ||
if (1.0 - cosom > EPSILON) { | ||
// standard case (slerp) | ||
omega = Math.acos(cosom); | ||
sinom = Math.sin(omega); | ||
scale0 = Math.sin((1.0 - t) * omega) / sinom; | ||
scale1 = Math.sin(t * omega) / sinom; | ||
} else { | ||
// "from" and "to" quaternions are very close | ||
// ... so we can do a linear interpolation | ||
scale0 = 1.0 - t; | ||
scale1 = t; | ||
} | ||
// calculate final values | ||
out[0] = scale0 * ax + scale1 * bx; | ||
out[1] = scale0 * ay + scale1 * by; | ||
out[2] = scale0 * az + scale1 * bz; | ||
out[3] = scale0 * aw + scale1 * bw; | ||
return out; | ||
} | ||
/** | ||
* Creates a quaternion from the given 3x3 rotation matrix. | ||
* | ||
* NOTE: The resultant quaternion is not normalized, so you should be sure | ||
* to renormalize the quaternion yourself where necessary. | ||
* | ||
* @param {quat} out the receiving quaternion | ||
* @param {mat3} m rotation matrix | ||
* @returns {quat} out | ||
* @function | ||
*/ | ||
function fromMat3(out, m) { | ||
// Algorithm in Ken Shoemake's article in 1987 SIGGRAPH course notes | ||
// article "Quaternion Calculus and Fast Animation". | ||
var fTrace = m[0] + m[4] + m[8]; | ||
var fRoot = void 0; | ||
if (fTrace > 0.0) { | ||
// |w| > 1/2, may as well choose w > 1/2 | ||
fRoot = Math.sqrt(fTrace + 1.0); // 2w | ||
out[3] = 0.5 * fRoot; | ||
fRoot = 0.5 / fRoot; // 1/(4w) | ||
out[0] = (m[5] - m[7]) * fRoot; | ||
out[1] = (m[6] - m[2]) * fRoot; | ||
out[2] = (m[1] - m[3]) * fRoot; | ||
} else { | ||
// |w| <= 1/2 | ||
var i = 0; | ||
if (m[4] > m[0]) i = 1; | ||
if (m[8] > m[i * 3 + i]) i = 2; | ||
var j = (i + 1) % 3; | ||
var k = (i + 2) % 3; | ||
fRoot = Math.sqrt(m[i * 3 + i] - m[j * 3 + j] - m[k * 3 + k] + 1.0); | ||
out[i] = 0.5 * fRoot; | ||
fRoot = 0.5 / fRoot; | ||
out[3] = (m[j * 3 + k] - m[k * 3 + j]) * fRoot; | ||
out[j] = (m[j * 3 + i] + m[i * 3 + j]) * fRoot; | ||
out[k] = (m[k * 3 + i] + m[i * 3 + k]) * fRoot; | ||
} | ||
return out; | ||
} | ||
/** | ||
* Normalize a quat | ||
* | ||
* @param {quat} out the receiving quaternion | ||
* @param {quat} a quaternion to normalize | ||
* @returns {quat} out | ||
* @function | ||
*/ | ||
var normalize$2 = normalize$1; | ||
/** | ||
* Sets a quaternion to represent the shortest rotation from one | ||
* vector to another. | ||
* | ||
* Both vectors are assumed to be unit length. | ||
* | ||
* @param {quat} out the receiving quaternion. | ||
* @param {vec3} a the initial vector | ||
* @param {vec3} b the destination vector | ||
* @returns {quat} out | ||
*/ | ||
var rotationTo = function () { | ||
var tmpvec3 = create$4(); | ||
var xUnitVec3 = fromValues$4(1, 0, 0); | ||
var yUnitVec3 = fromValues$4(0, 1, 0); | ||
return function (out, a, b) { | ||
var dot$$1 = dot(a, b); | ||
if (dot$$1 < -0.999999) { | ||
cross(tmpvec3, xUnitVec3, a); | ||
if (len(tmpvec3) < 0.000001) cross(tmpvec3, yUnitVec3, a); | ||
normalize(tmpvec3, tmpvec3); | ||
setAxisAngle(out, tmpvec3, Math.PI); | ||
return out; | ||
} else if (dot$$1 > 0.999999) { | ||
out[0] = 0; | ||
out[1] = 0; | ||
out[2] = 0; | ||
out[3] = 1; | ||
return out; | ||
} else { | ||
cross(tmpvec3, a, b); | ||
out[0] = tmpvec3[0]; | ||
out[1] = tmpvec3[1]; | ||
out[2] = tmpvec3[2]; | ||
out[3] = 1 + dot$$1; | ||
return normalize$2(out, out); | ||
} | ||
}; | ||
}(); | ||
/** | ||
* Performs a spherical linear interpolation with two control points | ||
* | ||
* @param {quat} out the receiving quaternion | ||
* @param {quat} a the first operand | ||
* @param {quat} b the second operand | ||
* @param {quat} c the third operand | ||
* @param {quat} d the fourth operand | ||
* @param {Number} t interpolation amount, in the range [0-1], between the two inputs | ||
* @returns {quat} out | ||
*/ | ||
var sqlerp = function () { | ||
var temp1 = create$6(); | ||
var temp2 = create$6(); | ||
return function (out, a, b, c, d, t) { | ||
slerp(temp1, a, d, t); | ||
slerp(temp2, b, c, t); | ||
slerp(out, temp1, temp2, 2 * t * (1 - t)); | ||
return out; | ||
}; | ||
}(); | ||
/** | ||
* Sets the specified quaternion with values corresponding to the given | ||
* axes. Each axis is a vec3 and is expected to be unit length and | ||
* perpendicular to all other specified axes. | ||
* | ||
* @param {vec3} view the vector representing the viewing direction | ||
* @param {vec3} right the vector representing the local "right" direction | ||
* @param {vec3} up the vector representing the local "up" direction | ||
* @returns {quat} out | ||
*/ | ||
var setAxes = function () { | ||
var matr = create$2(); | ||
return function (out, view, right, up) { | ||
matr[0] = right[0]; | ||
matr[3] = right[1]; | ||
matr[6] = right[2]; | ||
matr[1] = up[0]; | ||
matr[4] = up[1]; | ||
matr[7] = up[2]; | ||
matr[2] = -view[0]; | ||
matr[5] = -view[1]; | ||
matr[8] = -view[2]; | ||
return normalize$2(out, fromMat3(out, matr)); | ||
}; | ||
}(); | ||
/** | ||
* 2 Dimensional Vector | ||
* @module vec2 | ||
*/ | ||
/** | ||
* Creates a new, empty vec2 | ||
* | ||
* @returns {vec2} a new 2D vector | ||
*/ | ||
function create$8() { | ||
var out = new ARRAY_TYPE(2); | ||
if (ARRAY_TYPE != Float32Array) { | ||
out[0] = 0; | ||
out[1] = 0; | ||
} | ||
return out; | ||
} | ||
/** | ||
* Perform some operation over an array of vec2s. | ||
* | ||
* @param {Array} a the array of vectors to iterate over | ||
* @param {Number} stride Number of elements between the start of each vec2. If 0 assumes tightly packed | ||
* @param {Number} offset Number of elements to skip at the beginning of the array | ||
* @param {Number} count Number of vec2s to iterate over. If 0 iterates over entire array | ||
* @param {Function} fn Function to call for each vector in the array | ||
* @param {Object} [arg] additional argument to pass to fn | ||
* @returns {Array} a | ||
* @function | ||
*/ | ||
var forEach$2 = function () { | ||
var vec = create$8(); | ||
return function (a, stride, offset, count, fn, arg) { | ||
var i = void 0, | ||
l = void 0; | ||
if (!stride) { | ||
stride = 2; | ||
} | ||
if (!offset) { | ||
offset = 0; | ||
} | ||
if (count) { | ||
l = Math.min(count * stride + offset, a.length); | ||
} else { | ||
l = a.length; | ||
} | ||
for (i = offset; i < l; i += stride) { | ||
vec[0] = a[i];vec[1] = a[i + 1]; | ||
fn(vec, vec, arg); | ||
a[i] = vec[0];a[i + 1] = vec[1]; | ||
} | ||
return a; | ||
}; | ||
}(); | ||
const TWOPI = 2 * Math.PI; | ||
const Links = [['0.1'], ['3.1', [3042, 47]], ['4.1', [1375, 69]], ['5.1', [7357, 69]], ['5.2', | ||
[1849, 81]], ['6.1', [1534, 96]], ['6.2', [0, 82]], ['6.3', [10652, 85]], ['7.1', [7845, | ||
94]], ['7.2', [5595, 86]], ['7.3', [190, 122]], ['7.4', [3640, 102]], ['7.5', [1751, | ||
98]], ['7.6', [5020, 102]], ['7.7', [9660, 91]], ['8.1', [1279, 96]], ['8.2', [9751, | ||
108]], ['8.3', [2817, 112]], ['8.4', [3938, 105]], ['8.5', [4043, 105]], ['8.6', [4623, | ||
90]], ['8.7', [1191, 88]], ['8.8', [5681, 100]], ['8.9', [1930, 98]], ['8.10', [9031, | ||
85]], ['8.11', [1444, 90]], ['8.12', [4828, 94]], ['8.13', [6231, 90]], ['8.14', [885, | ||
98]], ['8.15', [9574, 86]], ['8.16', [4148, 85]], ['8.17', [312, 81]], ['8.18', [2243, | ||
97]], ['8.19', [6321, 86]], ['8.20', [7529, 88]], ['8.21', [686, 89]], ['9.1', [7013, | ||
102]], ['9.2', [10544, 108]], ['9.3', [4922, 98]], ['9.4', [3322, 89]], ['9.5', [3411, | ||
114]], ['9.6', [8182, 98]], ['9.7', [592, 94]], ['9.8', [10353, 91]], ['9.9', [2140, | ||
103]], ['9.10', [8392, 112]], ['9.11', [9349, 120]], ['9.12', [2929, 113]], ['9.13', | ||
[9116, 123]], ['9.14', [3089, 102]], ['9.15', [7939, 116]], ['9.16', [5462, 133]], | ||
['9.17', [10242, 111]], ['9.18', [82, 108]], ['9.19', [5122, 118]], ['9.20', [7725, | ||
120]], ['9.21', [486, 106]], ['9.22', [1630, 121]], ['9.23', [2436, 113]], ['9.24', | ||
[775, 110]], ['9.25', [6601, 102]], ['9.26', [3525, 115]], ['9.27', [6407, 89]], | ||
['9.28', [7426, 103]], ['9.29', [8280, 112]], ['9.30', [5781, 111]], ['9.31', [6703, | ||
120]], ['9.32', [8055, 127]], ['9.33', [7227, 130]], ['9.34', [4713, 115]], ['9.35', | ||
[3191, 131]], ['9.36', [5240, 119]], ['0.2.1'], ['2.2.1', [2648, 36], [2684, 36]], | ||
['4.2.1', [10161, 39], [10200, 42]], ['5.2.1', [8728, 38], [8766, 39]], ['6.2.1', [8931, | ||
49], [8980, 51]], ['6.2.2', [2340, 47], [2387, 49]], ['6.2.3', [3742, 41], [3783, 54]], | ||
['7.2.1', [9859, 44], [9903, 55]], ['7.2.2', [393, 45], [438, 48]], ['7.2.3', [6928, | ||
39], [6967, 46]], ['7.2.4', [6496, 77], [6573, 28]], ['7.2.5', [5892, 45], [5937, 68]], | ||
['7.2.6', [6823, 27], [6850, 78]], ['7.2.7', [10057, 78], [10135, 26]], ['7.2.8', [9239, | ||
43], [9282, 67]], ['8.2.1', [7115, 58], [7173, 54]], ['8.2.2', [6005, 53], [6058, 59]], | ||
['8.2.3', [8504, 42], [8546, 63]], ['8.2.4', [4357, 50], [4407, 57]], ['8.2.5', [9958, | ||
51], [10009, 48]], ['8.2.6', [10444, 46], [10490, 54]], ['8.2.7', [5359, 47], [5406, | ||
56]], ['8.2.8', [1097, 50], [1147, 44]], ['8.2.9', [2028, 42], [2070, 70]], ['8.2.10', | ||
[4233, 96], [4329, 28]], ['8.2.11', [6117, 93], [6210, 21]], ['0.3.1'], ['6.3.1', [3837, | ||
37], [3874, 31], [3905, 33]], ['6.3.2', [9469, 38], [9507, 34], [9541, 33]], ['6.3.3', | ||
[2720, 35], [2755, 30], [2785, 32]], ['7.3.1', [7617, 44], [7661, 33], [7694, 31]], | ||
['8.3.1', [8805, 45], [8850, 49], [8899, 32]], ['8.3.2', [8609, 45], [8654, 48], [8702, | ||
26]], ['8.3.3', [983, 43], [1026, 36], [1062, 35]], ['8.3.4', [4464, 28], [4492, 29], | ||
[4521, 102]], ['8.3.5', [2549, 26], [2575, 29], [2604, 44]]]; | ||
function perp(u, dest) { | ||
const v = [1, 0, 0]; | ||
cross(dest, u, v); | ||
const e = dot(dest, dest); | ||
if (e < 0.01) { | ||
copy$4(v, [0, 1, 0]); | ||
cross(dest, u, v); | ||
} | ||
return normalize(dest, dest); | ||
} | ||
function direction(vec, vec2$$1, dest) { | ||
if (!dest) { dest = vec; } | ||
let x = vec[0] - vec2$$1[0], | ||
y = vec[1] - vec2$$1[1], | ||
z = vec[2] - vec2$$1[2], | ||
len$$1 = Math.sqrt(x * x + y * y + z * z); | ||
if (!len$$1) { | ||
dest[0] = 0; | ||
dest[1] = 0; | ||
dest[2] = 0; | ||
return dest; | ||
} | ||
len$$1 = 1 / len$$1; | ||
dest[0] = x * len$$1; | ||
dest[1] = y * len$$1; | ||
dest[2] = z * len$$1; | ||
return dest; | ||
} | ||
function clamp(v,least,most) {return Math.max(Math.min(most,v),least)} | ||
function packSnorm16(value) {return Math.round(clamp(value,-1,1)*32767)} | ||
function vec4_packSnorm16(out,src) { | ||
out[0]=packSnorm16(src[0]); | ||
out[1]=packSnorm16(src[1]); | ||
out[2]=packSnorm16(src[2]); | ||
out[3]=packSnorm16(src[3]); | ||
return out | ||
} | ||
class Knotess { | ||
constructor(centerlines) { | ||
console.assert(ArrayBuffer.prototype.constructor === centerlines.constructor); | ||
this.spines = new Float32Array(centerlines); | ||
this.Rolfsen = [ | ||
'0.1 3.1 4.1 5.1 5.2 6.1 6.2 6.3 7.1', | ||
'7.2 7.3 7.4 7.5 7.6 7.7 8.1 8.2 8.3', | ||
'8.4 8.5 8.6 8.7 8.8 8.9 8.10 8.11 8.12', | ||
'8.13 8.14 8.15 8.16 8.17 8.18 8.19 8.20 8.21', | ||
'9.1 9.2 9.3 9.4 9.5 9.6 9.7 9.8 9.9', | ||
'9.10 9.11 9.12 9.13 9.14 9.15 9.16 9.17 9.18', | ||
'9.19 9.20 9.21 9.22 9.23 9.24 9.25 9.26 9.27', | ||
'9.28 9.29 9.30 9.31 9.32 9.33 9.34 9.35 9.36', | ||
'0.2.1 2.2.1 4.2.1 5.2.1 6.2.1 6.2.2 6.2.3 7.2.1 7.2.2', | ||
'7.2.3 7.2.4 7.2.5 7.2.6 7.2.7 7.2.8 8.2.1 8.2.2 8.2.3', | ||
'8.2.4 8.2.5 8.2.6 8.2.7 8.2.8 8.2.9 8.2.10 8.2.11 0.3.1', | ||
'6.3.1 6.3.2 6.3.3 7.3.1 8.3.1 8.3.2 8.3.3 8.3.4 8.3.5' | ||
]; | ||
this.LinearRolfsen = []; | ||
this.LinearRolfsenLookup = {}; | ||
for (const row of this.Rolfsen) { | ||
for (const id of row.split(' ')) { | ||
this.LinearRolfsenLookup[id] = this.LinearRolfsen.length; | ||
this.LinearRolfsen.push(id); | ||
} | ||
} | ||
this.LinksDb = {}; | ||
for (const link of Links) { | ||
this.LinksDb[link[0]] = link.slice(1); | ||
} | ||
} | ||
getPreviousLinkId(linkid) { | ||
const index = this.LinearRolfsenLookup[linkid]; | ||
return this.LinearRolfsen[Math.max(0, index - 1)]; | ||
} | ||
getNextLinkId(linkid) { | ||
const index = this.LinearRolfsenLookup[linkid]; | ||
const upper = this.LinearRolfsen.length - 1; | ||
return this.LinearRolfsen[Math.min(upper, index + 1)]; | ||
} | ||
// Given an Alexander-Briggs-Rolfsen identifier and an optional configuration dictionary, | ||
// returns an array of 'meshes' where each mesh is a dictionary with three entries: a | ||
// `Float32Array` vertex buffer, a `Uint16Array` triangle buffer, and (optionally) a | ||
// `Uint16Array` wireframe buffer. The vertex buffer is a flat array of PX PY PZ NX NY NZ. | ||
tessellate(linkid, options) { | ||
const defaults = { | ||
scale: 0.15, | ||
bézierSlices: 5, | ||
polygonSides: 10, | ||
radius: 0.07, | ||
wireframe: false, | ||
tangents: false, | ||
tangentSmoothness: 3 | ||
}; | ||
options = Object.assign(defaults, options); | ||
const ranges = this.LinksDb[linkid]; | ||
if (ranges.length) { | ||
return this.tessellateLink(ranges, options); | ||
} | ||
if (linkid == "0.1") { | ||
const mesh = this.tessellate("2.2.1", options)[0]; | ||
return [this.clone(mesh, [0.5, -0.25, 0])]; | ||
} | ||
if (linkid == "0.2.1") { | ||
const mesh = this.tessellate("2.2.1", options)[0]; | ||
return [ | ||
this.clone(mesh, [0, 0, 0]), | ||
this.clone(mesh, [0.5, 0, 0])]; | ||
} | ||
if (linkid == "0.3.1") { | ||
const mesh = this.tessellate("2.2.1", options)[0]; | ||
return [ | ||
this.clone(mesh, [0, 0, 0]), | ||
this.clone(mesh, [0.5, 0, 0]), | ||
this.clone(mesh, [1.0, 0, 0])]; | ||
} | ||
return []; | ||
} | ||
clone(mesh, translation) { | ||
const result = { | ||
vertices: new Float32Array(mesh.vertices), | ||
triangles: mesh.triangles, | ||
}; | ||
if (mesh.tangents) { | ||
result.tangents = new Uint16Array(mesh.tangents); | ||
} | ||
if (mesh.wireframe) { | ||
result.wireframe = new Uint16Array(mesh.wireframe); | ||
} | ||
const nverts = mesh.vertices.length / 6; | ||
for (let i = 0; i < nverts; i++) { | ||
result.vertices[i * 6 + 0] += translation[0]; | ||
result.vertices[i * 6 + 1] += translation[1]; | ||
result.vertices[i * 6 + 2] += translation[2]; | ||
} | ||
return result; | ||
} | ||
// Consumes an array of RANGE where RANGE = [INTEGER, INTEGER] | ||
// Produces an array of MESH where MESH = {vertices: Float32Array, triangles: Uint16Array} | ||
tessellateLink(ranges, options) { | ||
return ranges.map((range) => this.tessellateComponent(range, options)); | ||
} | ||
// Consumes [INTEGER, INTEGER] | ||
// Produces {vertices: Float32Array, triangles: Uint16Array} | ||
tessellateComponent(component, options) { | ||
let centerline, faceCount, i, j, lineCount, next, polygonCount; | ||
let polygonEdge, ptr, rawBuffer, segmentData, sides, sweepEdge, tri, triangles, tube, v; | ||
let wireframe = null; | ||
// Perform Bézier interpolation | ||
segmentData = this.spines.subarray(component[0] * 3, component[0] * 3 + component[1] * 3); | ||
centerline = this.getKnotPath(segmentData, options); | ||
// Create a positions buffer for a swept octagon | ||
rawBuffer = this.generateTube(centerline, options); | ||
tube = rawBuffer; | ||
// Create the index buffer for the tube wireframe | ||
polygonCount = centerline.length / 3 - 1; | ||
sides = options.polygonSides; | ||
lineCount = polygonCount * sides * 2; | ||
if (options.wireframe) { | ||
rawBuffer = new Uint16Array(lineCount * 2); | ||
[i, ptr] = [0, 0]; | ||
while (i < polygonCount * (sides + 1)) { | ||
j = 0; | ||
while (j < sides) { | ||
sweepEdge = rawBuffer.subarray(ptr + 2, ptr + 4); | ||
sweepEdge[0] = i + j; | ||
sweepEdge[1] = i + j + sides + 1; | ||
[ptr, j] = [ptr + 2, j + 1]; | ||
} | ||
i += sides + 1; | ||
} | ||
i = 0; | ||
while (i < polygonCount * (sides + 1)) { | ||
j = 0; | ||
while (j < sides) { | ||
polygonEdge = rawBuffer.subarray(ptr + 0, ptr + 2); | ||
polygonEdge[0] = i + j; | ||
polygonEdge[1] = i + j + 1; | ||
[ptr, j] = [ptr + 2, j + 1]; | ||
} | ||
i += sides + 1; | ||
} | ||
wireframe = rawBuffer; | ||
} | ||
// Create the index buffer for the solid tube | ||
faceCount = centerline.length / 3 * sides * 2; | ||
rawBuffer = new Uint16Array(faceCount * 3); | ||
[i, ptr, v] = [0, 0, 0]; | ||
while (++i < centerline.length / 3) { | ||
j = -1; | ||
while (++j < sides) { | ||
next = (j + 1) % sides; | ||
tri = rawBuffer.subarray(ptr + 0, ptr + 3); | ||
tri[0] = v + next + sides + 1; | ||
tri[1] = v + next; | ||
tri[2] = v + j; | ||
tri = rawBuffer.subarray(ptr + 3, ptr + 6); | ||
tri[0] = v + j; | ||
tri[1] = v + j + sides + 1; | ||
tri[2] = v + next + sides + 1; | ||
ptr += 6; | ||
} | ||
v += sides + 1; | ||
} | ||
triangles = rawBuffer; | ||
// Generate surface orientation quaternions. | ||
let tangents = null; | ||
if (options.tangents) { | ||
const nverts = tube.length / 6; | ||
tangents = new Uint16Array(4 * nverts); | ||
for (let i = 0; i < nverts; ++i) { | ||
const n = tube.subarray(i * 6 + 3, i * 6 + 6); | ||
const dst = tangents.subarray(i * 4, i * 4 + 4); | ||
const b = cross(create$4(), n, [1, 0, 0]); | ||
const t = cross(create$4(), b, n); | ||
const q = fromMat3([0, 0, 0, 1], [ | ||
t[0], t[1], t[2], | ||
b[0], b[1], b[2], | ||
n[0], n[1], n[2]]); | ||
vec4_packSnorm16(dst, q); | ||
} | ||
} | ||
return { | ||
vertices: tube, | ||
tangents: tangents, | ||
triangles: triangles, | ||
wireframe: wireframe | ||
}; | ||
} | ||
// Evaluate a Bézier function for smooth interpolation. | ||
// Return a Float32Array | ||
getKnotPath(data, options) { | ||
let a, b, c, dt, i, ii, j, k, l, n, p, r, rawBuffer, ref, slices, t, tt, v, v1, v2, v3, v4; | ||
let slice; | ||
slices = options.bézierSlices; | ||
rawBuffer = new Float32Array(data.length * slices + 3); | ||
[i, j] = [0, 0]; | ||
while (i < data.length + 3) { | ||
r = (function() { | ||
let k, len$$1, ref, results; | ||
ref = [0, 2, 3, 5, 6, 8]; | ||
results = []; | ||
for (k = 0, len$$1 = ref.length; k < len$$1; k++) { | ||
n = ref[k]; | ||
results.push((i + n) % data.length); | ||
} | ||
return results; | ||
})(); | ||
a = data.subarray(r[0], r[1] + 1); | ||
b = data.subarray(r[2], r[3] + 1); | ||
c = data.subarray(r[4], r[5] + 1); | ||
v1 = clone$4(a); | ||
v4 = clone$4(b); | ||
lerp(v1, v1, b, 0.5); | ||
lerp(v4, v4, c, 0.5); | ||
v2 = clone$4(v1); | ||
v3 = clone$4(v4); | ||
lerp(v2, v2, b, 1 / 3); | ||
lerp(v3, v3, b, 1 / 3); | ||
t = dt = 1 / (slices + 1); | ||
for (slice = k = 0, ref = slices; (0 <= ref ? k < ref : k > ref); | ||
slice = 0 <= ref ? ++k : --k) { | ||
tt = 1 - t; | ||
c = [tt * tt * tt, 3 * tt * tt * t, 3 * tt * t * t, t * t * t]; | ||
p = (function() { | ||
let l, len$$1, ref1, results; | ||
ref1 = [v1, v2, v3, v4]; | ||
results = []; | ||
for (l = 0, len$$1 = ref1.length; l < len$$1; l++) { | ||
v = ref1[l]; | ||
results.push(clone$4(v)); | ||
} | ||
return results; | ||
})(); | ||
for (ii = l = 0; l < 4; ii = ++l) { | ||
scale$4(p[ii], p[ii], c[ii]); | ||
} | ||
p = p.reduce(function(a, b) { | ||
return add$4(a, a, b); | ||
}); | ||
scale$4(p, p, options.scale); | ||
rawBuffer.set(p, j); | ||
j += 3; | ||
if (j >= rawBuffer.length) { | ||
return rawBuffer; | ||
} | ||
t += dt; | ||
} | ||
i += 3; | ||
} | ||
} | ||
// Sweep a n-sided polygon along the given centerline. | ||
// Returns the mesh verts as a Float32Arrays. | ||
// Repeats the vertex along the seam to allow nice texture coords. | ||
generateTube(centerline, options) { | ||
let B, C, basis, center, count, dtheta, frames, i, m, mesh, n, normal, p, r, theta; | ||
let v, x, y, z; | ||
n = options.polygonSides; | ||
dtheta = TWOPI / n; | ||
frames = this.generateFrames(centerline, options); | ||
count = centerline.length / 3; | ||
mesh = new Float32Array(count * (n + 1) * 6); | ||
[i, m] = [0, 0]; | ||
p = create$4(); | ||
r = options.radius; | ||
while (i < count) { | ||
v = 0; | ||
basis = (function() { | ||
let k, results; | ||
results = []; | ||
for (C = k = 0; k <= 2; C = ++k) { | ||
results.push(frames[C].subarray(i * 3, i * 3 + 3)); | ||
} | ||
return results; | ||
})(); | ||
basis = (function() { | ||
let k, len$$1, results; | ||
results = []; | ||
for (k = 0, len$$1 = basis.length; k < len$$1; k++) { | ||
B = basis[k]; | ||
results.push((function() { | ||
let l, results1; | ||
results1 = []; | ||
for (C = l = 0; l <= 2; C = ++l) { | ||
results1.push(B[C]); | ||
} | ||
return results1; | ||
})()); | ||
} | ||
return results; | ||
})(); | ||
basis = basis.reduce(function(A, B) { | ||
return A.concat(B); | ||
}); | ||
theta = 0; | ||
while (v < n + 1) { | ||
x = r * Math.cos(theta); | ||
y = r * Math.sin(theta); | ||
z = 0; | ||
transformMat3(p, [x, y, z], basis); | ||
p[0] += centerline[i * 3 + 0]; | ||
p[1] += centerline[i * 3 + 1]; | ||
p[2] += centerline[i * 3 + 2]; | ||
// Stamp p into 'm', skipping over the normal: | ||
mesh.set(p, m); | ||
[m, v, theta] = [m + 6, v + 1, theta + dtheta]; | ||
} | ||
i++; | ||
} | ||
// Next, populate normals: | ||
[i, m] = [0, 0]; | ||
normal = create$4(); | ||
center = create$4(); | ||
while (i < count) { | ||
v = 0; | ||
while (v < n + 1) { | ||
p[0] = mesh[m + 0]; | ||
p[1] = mesh[m + 1]; | ||
p[2] = mesh[m + 2]; | ||
center[0] = centerline[i * 3 + 0]; | ||
center[1] = centerline[i * 3 + 1]; | ||
center[2] = centerline[i * 3 + 2]; | ||
direction(p, center, normal); | ||
// Stamp n into 'm', skipping over the position: | ||
mesh.set(normal, m + 3); | ||
[m, v] = [m + 6, v + 1]; | ||
} | ||
i++; | ||
} | ||
return mesh; | ||
} | ||
// Generate reasonable orthonormal basis vectors for curve in R3. | ||
// Returns three lists-of-vec3's for the basis vectors. | ||
// See 'Computation of Rotation Minimizing Frame' by Wang and Jüttler. | ||
generateFrames(centerline, options) { | ||
let count, frameR, frameS, frameT, i, j, n, r0, ri, rj, s0, si, sj, t0, ti, tj, xi, xj; | ||
count = centerline.length / 3; | ||
frameR = new Float32Array(count * 3); | ||
frameS = new Float32Array(count * 3); | ||
frameT = new Float32Array(count * 3); | ||
// Obtain unit-length tangent vectors | ||
i = -1; | ||
while (++i < count) { | ||
j = (i + 1 + options.tangentSmoothness) % (count - 1); | ||
xi = centerline.subarray(i * 3, i * 3 + 3); | ||
xj = centerline.subarray(j * 3, j * 3 + 3); | ||
ti = frameT.subarray(i * 3, i * 3 + 3); | ||
direction(xi, xj, ti); | ||
} | ||
// Allocate some temporaries for vector math | ||
[r0, s0, t0] = (function() { | ||
let k, results; | ||
results = []; | ||
for (n = k = 0; k <= 2; n = ++k) { | ||
results.push(create$4()); | ||
} | ||
return results; | ||
})(); | ||
[rj, sj, tj] = (function() { | ||
let k, results; | ||
results = []; | ||
for (n = k = 0; k <= 2; n = ++k) { | ||
results.push(create$4()); | ||
} | ||
return results; | ||
})(); | ||
// Create a somewhat-arbitrary initial frame (r0, s0, t0) | ||
copy$4(t0, frameT.subarray(0, 3)); | ||
perp(t0, r0); | ||
cross(s0, t0, r0); | ||
normalize(r0, r0); | ||
normalize(s0, s0); | ||
copy$4(frameR.subarray(0, 3), r0); | ||
copy$4(frameS.subarray(0, 3), s0); | ||
// Use parallel transport to sweep the frame | ||
// TODO: add minor twist so that a swept triangle aligns without cracks. | ||
[i, j] = [0, 1]; | ||
[ri, si, ti] = [r0, s0, t0]; | ||
while (i < count - 1) { | ||
j = i + 1; | ||
xi = centerline.subarray(i * 3, i * 3 + 3); | ||
xj = centerline.subarray(j * 3, j * 3 + 3); | ||
ti = frameT.subarray(i * 3, i * 3 + 3); | ||
tj = frameT.subarray(j * 3, j * 3 + 3); | ||
cross(sj, tj, ri); | ||
normalize(sj, sj); | ||
cross(rj, sj, tj); | ||
copy$4(frameR.subarray(j * 3, j * 3 + 3), rj); | ||
copy$4(frameS.subarray(j * 3, j * 3 + 3), sj); | ||
copy$4(ri, rj); | ||
++i; | ||
} | ||
// Return the basis columns | ||
return [frameR, frameS, frameT]; | ||
} | ||
} | ||
return Knotess; | ||
}))); | ||
!function(r,t){"object"==typeof exports&&"undefined"!=typeof module?module.exports=t():"function"==typeof define&&define.amd?define(t):r.Knotess=t()}(this,function(){"use strict";var r=1e-6,t="undefined"!=typeof Float32Array?Float32Array:Array;Math.PI;function n(){var r=new t(3);return t!=Float32Array&&(r[0]=0,r[1]=0,r[2]=0),r}function e(r){var n=new t(3);return n[0]=r[0],n[1]=r[1],n[2]=r[2],n}function s(r,n,e){var s=new t(3);return s[0]=r,s[1]=n,s[2]=e,s}function a(r,t){return r[0]=t[0],r[1]=t[1],r[2]=t[2],r}function o(r,t,n){return r[0]=t[0]+n[0],r[1]=t[1]+n[1],r[2]=t[2]+n[2],r}function i(r,t,n){return r[0]=t[0]*n,r[1]=t[1]*n,r[2]=t[2]*n,r}function u(r,t){var n=t[0],e=t[1],s=t[2],a=n*n+e*e+s*s;return a>0&&(a=1/Math.sqrt(a),r[0]=t[0]*a,r[1]=t[1]*a,r[2]=t[2]*a),r}function l(r,t){return r[0]*t[0]+r[1]*t[1]+r[2]*t[2]}function f(r,t,n){var e=t[0],s=t[1],a=t[2],o=n[0],i=n[1],u=n[2];return r[0]=s*u-a*i,r[1]=a*o-e*u,r[2]=e*i-s*o,r}function c(r,t,n,e){var s=t[0],a=t[1],o=t[2];return r[0]=s+e*(n[0]-s),r[1]=a+e*(n[1]-a),r[2]=o+e*(n[2]-o),r}function h(r,t,n){var e=t[0],s=t[1],a=t[2];return r[0]=e*n[0]+s*n[3]+a*n[6],r[1]=e*n[1]+s*n[4]+a*n[7],r[2]=e*n[2]+s*n[5]+a*n[8],r}var y,g=function(r){var t=r[0],n=r[1],e=r[2];return Math.sqrt(t*t+n*n+e*e)};y=n();!function(){var r,n=(r=new t(4),t!=Float32Array&&(r[0]=0,r[1]=0,r[2]=0,r[3]=0),r)}();function v(){var r=new t(4);return t!=Float32Array&&(r[0]=0,r[1]=0,r[2]=0),r[3]=1,r}function b(t,n,e,s){var a=n[0],o=n[1],i=n[2],u=n[3],l=e[0],f=e[1],c=e[2],h=e[3],y=void 0,g=void 0,v=void 0,b=void 0,p=void 0;return(g=a*l+o*f+i*c+u*h)<0&&(g=-g,l=-l,f=-f,c=-c,h=-h),1-g>r?(y=Math.acos(g),v=Math.sin(y),b=Math.sin((1-s)*y)/v,p=Math.sin(s*y)/v):(b=1-s,p=s),t[0]=b*a+p*l,t[1]=b*o+p*f,t[2]=b*i+p*c,t[3]=b*u+p*h,t}function p(r,t){var n=t[0]+t[4]+t[8],e=void 0;if(n>0)e=Math.sqrt(n+1),r[3]=.5*e,e=.5/e,r[0]=(t[5]-t[7])*e,r[1]=(t[6]-t[2])*e,r[2]=(t[1]-t[3])*e;else{var s=0;t[4]>t[0]&&(s=1),t[8]>t[3*s+s]&&(s=2);var a=(s+1)%3,o=(s+2)%3;e=Math.sqrt(t[3*s+s]-t[3*a+a]-t[3*o+o]+1),r[s]=.5*e,e=.5/e,r[3]=(t[3*a+o]-t[3*o+a])*e,r[a]=(t[3*a+s]+t[3*s+a])*e,r[o]=(t[3*o+s]+t[3*s+o])*e}return r}var d,w,A,L,m,M,F,R=function(r,t){var n=t[0],e=t[1],s=t[2],a=t[3],o=n*n+e*e+s*s+a*a;return o>0&&(o=1/Math.sqrt(o),r[0]=n*o,r[1]=e*o,r[2]=s*o,r[3]=a*o),r};d=n(),w=s(1,0,0),A=s(0,1,0),L=v(),m=v(),M=new t(9),t!=Float32Array&&(M[1]=0,M[2]=0,M[3]=0,M[5]=0,M[6]=0,M[7]=0),M[0]=1,M[4]=1,M[8]=1,F=M;!function(){var r,n=(r=new t(2),t!=Float32Array&&(r[0]=0,r[1]=0),r)}();const k=2*Math.PI,S=[["0.1"],["3.1",[3042,47]],["4.1",[1375,69]],["5.1",[7357,69]],["5.2",[1849,81]],["6.1",[1534,96]],["6.2",[0,82]],["6.3",[10652,85]],["7.1",[7845,94]],["7.2",[5595,86]],["7.3",[190,122]],["7.4",[3640,102]],["7.5",[1751,98]],["7.6",[5020,102]],["7.7",[9660,91]],["8.1",[1279,96]],["8.2",[9751,108]],["8.3",[2817,112]],["8.4",[3938,105]],["8.5",[4043,105]],["8.6",[4623,90]],["8.7",[1191,88]],["8.8",[5681,100]],["8.9",[1930,98]],["8.10",[9031,85]],["8.11",[1444,90]],["8.12",[4828,94]],["8.13",[6231,90]],["8.14",[885,98]],["8.15",[9574,86]],["8.16",[4148,85]],["8.17",[312,81]],["8.18",[2243,97]],["8.19",[6321,86]],["8.20",[7529,88]],["8.21",[686,89]],["9.1",[7013,102]],["9.2",[10544,108]],["9.3",[4922,98]],["9.4",[3322,89]],["9.5",[3411,114]],["9.6",[8182,98]],["9.7",[592,94]],["9.8",[10353,91]],["9.9",[2140,103]],["9.10",[8392,112]],["9.11",[9349,120]],["9.12",[2929,113]],["9.13",[9116,123]],["9.14",[3089,102]],["9.15",[7939,116]],["9.16",[5462,133]],["9.17",[10242,111]],["9.18",[82,108]],["9.19",[5122,118]],["9.20",[7725,120]],["9.21",[486,106]],["9.22",[1630,121]],["9.23",[2436,113]],["9.24",[775,110]],["9.25",[6601,102]],["9.26",[3525,115]],["9.27",[6407,89]],["9.28",[7426,103]],["9.29",[8280,112]],["9.30",[5781,111]],["9.31",[6703,120]],["9.32",[8055,127]],["9.33",[7227,130]],["9.34",[4713,115]],["9.35",[3191,131]],["9.36",[5240,119]],["0.2.1"],["2.2.1",[2648,36],[2684,36]],["4.2.1",[10161,39],[10200,42]],["5.2.1",[8728,38],[8766,39]],["6.2.1",[8931,49],[8980,51]],["6.2.2",[2340,47],[2387,49]],["6.2.3",[3742,41],[3783,54]],["7.2.1",[9859,44],[9903,55]],["7.2.2",[393,45],[438,48]],["7.2.3",[6928,39],[6967,46]],["7.2.4",[6496,77],[6573,28]],["7.2.5",[5892,45],[5937,68]],["7.2.6",[6823,27],[6850,78]],["7.2.7",[10057,78],[10135,26]],["7.2.8",[9239,43],[9282,67]],["8.2.1",[7115,58],[7173,54]],["8.2.2",[6005,53],[6058,59]],["8.2.3",[8504,42],[8546,63]],["8.2.4",[4357,50],[4407,57]],["8.2.5",[9958,51],[10009,48]],["8.2.6",[10444,46],[10490,54]],["8.2.7",[5359,47],[5406,56]],["8.2.8",[1097,50],[1147,44]],["8.2.9",[2028,42],[2070,70]],["8.2.10",[4233,96],[4329,28]],["8.2.11",[6117,93],[6210,21]],["0.3.1"],["6.3.1",[3837,37],[3874,31],[3905,33]],["6.3.2",[9469,38],[9507,34],[9541,33]],["6.3.3",[2720,35],[2755,30],[2785,32]],["7.3.1",[7617,44],[7661,33],[7694,31]],["8.3.1",[8805,45],[8850,49],[8899,32]],["8.3.2",[8609,45],[8654,48],[8702,26]],["8.3.3",[983,43],[1026,36],[1062,35]],["8.3.4",[4464,28],[4492,29],[4521,102]],["8.3.5",[2549,26],[2575,29],[2604,44]]];function q(r,t,n){n||(n=r);let e=r[0]-t[0],s=r[1]-t[1],a=r[2]-t[2],o=Math.sqrt(e*e+s*s+a*a);return o?(o=1/o,n[0]=e*o,n[1]=s*o,n[2]=a*o,n):(n[0]=0,n[1]=0,n[2]=0,n)}function x(r){return Math.round(32767*(t=r,n=-1,e=1,Math.max(Math.min(e,t),n)));var t,n,e}return class{constructor(r){console.assert(ArrayBuffer.prototype.constructor===r.constructor),this.spines=new Float32Array(r),this.Rolfsen=["0.1 3.1 4.1 5.1 5.2 6.1 6.2 6.3 7.1","7.2 7.3 7.4 7.5 7.6 7.7 8.1 8.2 8.3","8.4 8.5 8.6 8.7 8.8 8.9 8.10 8.11 8.12","8.13 8.14 8.15 8.16 8.17 8.18 8.19 8.20 8.21","9.1 9.2 9.3 9.4 9.5 9.6 9.7 9.8 9.9","9.10 9.11 9.12 9.13 9.14 9.15 9.16 9.17 9.18","9.19 9.20 9.21 9.22 9.23 9.24 9.25 9.26 9.27","9.28 9.29 9.30 9.31 9.32 9.33 9.34 9.35 9.36","0.2.1 2.2.1 4.2.1 5.2.1 6.2.1 6.2.2 6.2.3 7.2.1 7.2.2","7.2.3 7.2.4 7.2.5 7.2.6 7.2.7 7.2.8 8.2.1 8.2.2 8.2.3","8.2.4 8.2.5 8.2.6 8.2.7 8.2.8 8.2.9 8.2.10 8.2.11 0.3.1","6.3.1 6.3.2 6.3.3 7.3.1 8.3.1 8.3.2 8.3.3 8.3.4 8.3.5"],this.LinearRolfsen=[],this.LinearRolfsenLookup={};for(const r of this.Rolfsen)for(const t of r.split(" "))this.LinearRolfsenLookup[t]=this.LinearRolfsen.length,this.LinearRolfsen.push(t);this.LinksDb={};for(const r of S)this.LinksDb[r[0]]=r.slice(1)}getPreviousLinkId(r){const t=this.LinearRolfsenLookup[r];return this.LinearRolfsen[Math.max(0,t-1)]}getNextLinkId(r){const t=this.LinearRolfsenLookup[r],n=this.LinearRolfsen.length-1;return this.LinearRolfsen[Math.min(n,t+1)]}tessellate(r,t){t=Object.assign({scale:.15,"bézierSlices":5,polygonSides:10,radius:.07,wireframe:!1,tangents:!1,tangentSmoothness:3},t);const n=this.LinksDb[r];if(n.length)return this.tessellateLink(n,t);if("0.1"==r){const r=this.tessellate("2.2.1",t)[0];return[this.clone(r,[.5,-.25,0])]}if("0.2.1"==r){const r=this.tessellate("2.2.1",t)[0];return[this.clone(r,[0,0,0]),this.clone(r,[.5,0,0])]}if("0.3.1"==r){const r=this.tessellate("2.2.1",t)[0];return[this.clone(r,[0,0,0]),this.clone(r,[.5,0,0]),this.clone(r,[1,0,0])]}return[]}clone(r,t){const n={vertices:new Float32Array(r.vertices),triangles:r.triangles};r.tangents&&(n.tangents=new Uint16Array(r.tangents)),r.wireframe&&(n.wireframe=new Uint16Array(r.wireframe));const e=r.vertices.length/6;for(let r=0;r<e;r++)n.vertices[6*r+0]+=t[0],n.vertices[6*r+1]+=t[1],n.vertices[6*r+2]+=t[2];return n}tessellateLink(r,t){return r.map(r=>this.tessellateComponent(r,t))}tessellateComponent(r,t){let e,s,a,o,i,u,l,c,h,y,g,v,b,d,w,A,L,m=null;if(g=this.spines.subarray(3*r[0],3*r[0]+3*r[1]),e=this.getKnotPath(g,t),A=y=this.generateTube(e,t),i=(l=e.length/3-1)*(v=t.polygonSides)*2,t.wireframe){for(y=new Uint16Array(2*i),[a,h]=[0,0];a<l*(v+1);){for(o=0;o<v;)(b=y.subarray(h+2,h+4))[0]=a+o,b[1]=a+o+v+1,[h,o]=[h+2,o+1];a+=v+1}for(a=0;a<l*(v+1);){for(o=0;o<v;)(c=y.subarray(h+0,h+2))[0]=a+o,c[1]=a+o+1,[h,o]=[h+2,o+1];a+=v+1}m=y}for(s=e.length/3*v*2,y=new Uint16Array(3*s),[a,h,L]=[0,0,0];++a<e.length/3;){for(o=-1;++o<v;)u=(o+1)%v,(d=y.subarray(h+0,h+3))[0]=L+u+v+1,d[1]=L+u,d[2]=L+o,(d=y.subarray(h+3,h+6))[0]=L+o,d[1]=L+o+v+1,d[2]=L+u+v+1,h+=6;L+=v+1}w=y;let M=null;if(t.tangents){const r=A.length/6;M=new Uint16Array(4*r);for(let t=0;t<r;++t){const r=A.subarray(6*t+3,6*t+6),e=M.subarray(4*t,4*t+4),s=f(n(),r,[1,0,0]),a=f(n(),s,r),o=p([0,0,0,1],[a[0],a[1],a[2],s[0],s[1],s[2],r[0],r[1],r[2]]);R=o,(F=e)[0]=x(R[0]),F[1]=x(R[1]),F[2]=x(R[2]),F[3]=x(R[3])}}var F,R;return{vertices:A,tangents:M,triangles:w,wireframe:m}}getKnotPath(r,t){let n,s,a,u,l,f,h,y,g,v,b,p,d,w,A,L,m,M,F,R,k,S,q;for(A=t.bézierSlices,d=new Float32Array(r.length*A+3),[l,h]=[0,0];l<r.length+3;){for(p=function(){let t,n,e,s;for(s=[],t=0,n=(e=[0,2,3,5,6,8]).length;t<n;t++)v=e[t],s.push((l+v)%r.length);return s}(),n=r.subarray(p[0],p[1]+1),s=r.subarray(p[2],p[3]+1),a=r.subarray(p[4],p[5]+1),F=e(n),S=e(s),c(F,F,s,.5),c(S,S,a,.5),R=e(F),k=e(S),c(R,R,s,1/3),c(k,k,s,1/3),L=u=1/(A+1),q=y=0,w=A;0<=w?y<w:y>w;q=0<=w?++y:--y){for(a=[(m=1-L)*m*m,3*m*m*L,3*m*L*L,L*L*L],b=function(){let r,t,n,s;for(s=[],r=0,t=(n=[F,R,k,S]).length;r<t;r++)M=n[r],s.push(e(M));return s}(),f=g=0;g<4;f=++g)i(b[f],b[f],a[f]);if(i(b=b.reduce(function(r,t){return o(r,r,t)}),b,t.scale),d.set(b,h),(h+=3)>=d.length)return d;L+=u}l+=3}}generateTube(r,t){let e,s,a,o,i,u,l,f,c,y,g,v,b,p,d,w,A,L,m;for(g=t.polygonSides,u=k/g,l=this.generateFrames(r,t),i=r.length/3,y=new Float32Array(i*(g+1)*6),[f,c]=[0,0],b=n(),p=t.radius;f<i;){for(w=0,a=function(){let r,t;for(t=[],s=r=0;r<=2;s=++r)t.push(l[s].subarray(3*f,3*f+3));return t}(),a=(a=function(){let r,t,n;for(n=[],r=0,t=a.length;r<t;r++)e=a[r],n.push(function(){let r,t;for(t=[],s=r=0;r<=2;s=++r)t.push(e[s]);return t}());return n}()).reduce(function(r,t){return r.concat(t)}),d=0;w<g+1;)m=0,h(b,[A=p*Math.cos(d),L=p*Math.sin(d),0],a),b[0]+=r[3*f+0],b[1]+=r[3*f+1],b[2]+=r[3*f+2],y.set(b,c),[c,w,d]=[c+6,w+1,d+u];f++}for([f,c]=[0,0],v=n(),o=n();f<i;){for(w=0;w<g+1;)b[0]=y[c+0],b[1]=y[c+1],b[2]=y[c+2],o[0]=r[3*f+0],o[1]=r[3*f+1],o[2]=r[3*f+2],q(b,o,v),y.set(v,c+3),[c,w]=[c+6,w+1];f++}return y}generateFrames(r,t){let e,s,o,i,c,h,y,g,v,b,p,d,w,A,L,m,M,F;for(e=r.length/3,s=new Float32Array(3*e),o=new Float32Array(3*e),i=new Float32Array(3*e),c=-1;++c<e;)h=(c+1+t.tangentSmoothness)%(e-1),q(M=r.subarray(3*c,3*c+3),F=r.subarray(3*h,3*h+3),L=i.subarray(3*c,3*c+3));for([g,p,A]=function(){let r,t;for(t=[],y=r=0;r<=2;y=++r)t.push(n());return t}(),[b,w,m]=function(){let r,t;for(t=[],y=r=0;r<=2;y=++r)t.push(n());return t}(),a(A,i.subarray(0,3)),function(r,t){const n=[1,0,0];f(t,r,n),l(t,t)<.01&&(a(n,[0,1,0]),f(t,r,n)),u(t,t)}(A,g),f(p,A,g),u(g,g),u(p,p),a(s.subarray(0,3),g),a(o.subarray(0,3),p),[c,h]=[0,1],[v,d,L]=[g,p,A];c<e-1;)h=c+1,M=r.subarray(3*c,3*c+3),F=r.subarray(3*h,3*h+3),L=i.subarray(3*c,3*c+3),f(w,m=i.subarray(3*h,3*h+3),v),u(w,w),f(b,w,m),a(s.subarray(3*h,3*h+3),b),a(o.subarray(3*h,3*h+3),w),a(v,b),++c;return[s,o,i]}}}); |
{ | ||
"name": "knotess", | ||
"version": "1.1.0", | ||
"version": "1.1.1", | ||
"description": "Tessellate mathematical knots in JavaScript", | ||
@@ -5,0 +5,0 @@ "main": "knotess.js", |
@@ -33,7 +33,7 @@ <h1>Knotess<img src="https://upload.wikimedia.org/wikipedia/commons/0/05/Blue_Figure-Eight_Knot.png" align="right" width="128"></h1> | ||
Or use a browser build directly as follows. Note the external dependency on [glMatrix]. | ||
Or use a browser build directly as follows. | ||
```html | ||
<script src="//unpkg.com/gl-matrix@2.8.1/dist/gl-matrix-min.js"></script> | ||
<script src="//unpkg.com/knotess@1.0.0/knotess.js"></script> | ||
<script src="//unpkg.com/knotess@1.1.1/knotess.min.js"></script> <!-- minified build --> | ||
<script src="//unpkg.com/knotess@1.1.1/knotess.js"></script> <!-- dev build --> | ||
``` | ||
@@ -40,0 +40,0 @@ |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
155223
84