Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

knotess

Package Overview
Dependencies
Maintainers
1
Versions
5
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

knotess - npm Package Compare versions

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]}}});

@@ -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]}}});

2

package.json
{
"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 @@

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc