@ccp-nc/crystvis-js 0.4.13
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.eslintrc.json +16 -0
- package/.github/workflows/test-mocha.yml +30 -0
- package/.vscode/settings.json +4 -0
- package/LICENSE +21 -0
- package/README.html +1127 -0
- package/README.md +76 -0
- package/demo/demo.css +30 -0
- package/demo/index.html +76 -0
- package/demo/main.js +143 -0
- package/docs/.nojekyll +0 -0
- package/docs-tutorials/Events.md +57 -0
- package/docs-tutorials/Queries.md +50 -0
- package/fonts/Rubik/OFL.txt +93 -0
- package/fonts/Rubik/README.txt +77 -0
- package/fonts/Rubik/Rubik-Italic-VariableFont_wght.ttf +0 -0
- package/fonts/Rubik/Rubik-VariableFont_wght.ttf +0 -0
- package/fonts/Rubik/static/Rubik-Black.ttf +0 -0
- package/fonts/Rubik/static/Rubik-BlackItalic.ttf +0 -0
- package/fonts/Rubik/static/Rubik-Bold.ttf +0 -0
- package/fonts/Rubik/static/Rubik-BoldItalic.ttf +0 -0
- package/fonts/Rubik/static/Rubik-ExtraBold.ttf +0 -0
- package/fonts/Rubik/static/Rubik-ExtraBoldItalic.ttf +0 -0
- package/fonts/Rubik/static/Rubik-Italic.ttf +0 -0
- package/fonts/Rubik/static/Rubik-Light.ttf +0 -0
- package/fonts/Rubik/static/Rubik-LightItalic.ttf +0 -0
- package/fonts/Rubik/static/Rubik-Medium.ttf +0 -0
- package/fonts/Rubik/static/Rubik-MediumItalic.ttf +0 -0
- package/fonts/Rubik/static/Rubik-Regular.ttf +0 -0
- package/fonts/Rubik/static/Rubik-SemiBold.ttf +0 -0
- package/fonts/Rubik/static/Rubik-SemiBoldItalic.ttf +0 -0
- package/index.html +25 -0
- package/index.js +11 -0
- package/jsconf.json +14 -0
- package/lib/assets/fonts/Rubik-Medium.fnt +297 -0
- package/lib/assets/fonts/Rubik-Medium.png +0 -0
- package/lib/assets/fonts/bmpfonts.in.js +16 -0
- package/lib/assets/fonts/bmpfonts.js +9 -0
- package/lib/assets/fonts/font.js +82 -0
- package/lib/assets/fonts/index.js +14 -0
- package/lib/assets/fonts/threebmfont.js +28 -0
- package/lib/data.js +125 -0
- package/lib/formats/cell.js +114 -0
- package/lib/formats/cif.js +22 -0
- package/lib/formats/magres.js +337 -0
- package/lib/formats/xyz.js +124 -0
- package/lib/loader.js +87 -0
- package/lib/model.js +2076 -0
- package/lib/modelview.js +382 -0
- package/lib/nmrdata.js +2898 -0
- package/lib/orbit.js +1233 -0
- package/lib/primitives/atoms.js +261 -0
- package/lib/primitives/cell.js +160 -0
- package/lib/primitives/dither.js +156 -0
- package/lib/primitives/ellipsoid.js +183 -0
- package/lib/primitives/geometries.js +20 -0
- package/lib/primitives/index.js +48 -0
- package/lib/primitives/isosurface.js +171 -0
- package/lib/primitives/shapes.js +100 -0
- package/lib/primitives/sprites.js +172 -0
- package/lib/query.js +158 -0
- package/lib/render.js +440 -0
- package/lib/selbox.js +361 -0
- package/lib/shaders/aura.frag +26 -0
- package/lib/shaders/aura.vert +37 -0
- package/lib/shaders/dither.frag +42 -0
- package/lib/shaders/dither.vert +8 -0
- package/lib/shaders/index.in.js +17 -0
- package/lib/shaders/index.js +25 -0
- package/lib/shaders/msdf300.frag +25 -0
- package/lib/shaders/msdf300.vert +45 -0
- package/lib/tensor.js +227 -0
- package/lib/utils.js +168 -0
- package/lib/visualizer.js +480 -0
- package/package.json +106 -0
- package/scripts/build-bundle.js +17 -0
- package/scripts/build-fonts.js +43 -0
- package/scripts/build-resources.js +46 -0
- package/scripts/plugins-shim.js +10 -0
- package/test/chemdata.js +69 -0
- package/test/data/CHA.cif +74 -0
- package/test/data/H2O.xyz +8 -0
- package/test/data/H2_bound.xyz +4 -0
- package/test/data/ethanol.cell +25 -0
- package/test/data/ethanol.magres +238 -0
- package/test/data/example_single.cif +789 -0
- package/test/data/frac.cell +8 -0
- package/test/data/org.cif +427 -0
- package/test/data/pyridine.xyz +13 -0
- package/test/data/si8.xyz +10 -0
- package/test/loader.js +107 -0
- package/test/model.js +368 -0
- package/test/query.js +135 -0
- package/test/tensor.js +133 -0
- package/test/test-html/examples.js +1485 -0
- package/test/test-html/index.html +33 -0
- package/test/test-html/index.js +279 -0
- package/tools/compile_colors.py +120 -0
- package/tools/compile_periodic.py +96 -0
- package/tools/ptable.json +497 -0
- package/tools/test +5844 -0
package/lib/tensor.js
ADDED
|
@@ -0,0 +1,227 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* @fileoverview TensorData class to store tensors like NMR data and such.
|
|
5
|
+
* @module
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import _ from 'lodash';
|
|
9
|
+
import * as mjs from 'mathjs';
|
|
10
|
+
import * as THREE from 'three';
|
|
11
|
+
|
|
12
|
+
const efg2hz = 234964.77815245767;
|
|
13
|
+
const isc2hz = 1.6784031762379067e-16; // hbar/(2*pi)*1e19
|
|
14
|
+
|
|
15
|
+
class TensorData {
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Create a TensorData object, to store whole tensors,
|
|
19
|
+
* diagonalise their symmetric part and return derived quantities
|
|
20
|
+
*
|
|
21
|
+
* @param {Array | mathjs.Matrix | TensorData} M Tensor in 3x3 matrix form
|
|
22
|
+
*
|
|
23
|
+
*/
|
|
24
|
+
constructor(M) {
|
|
25
|
+
|
|
26
|
+
if (M instanceof TensorData)
|
|
27
|
+
M = M._M;
|
|
28
|
+
else if (M instanceof Array)
|
|
29
|
+
M = mjs.matrix(M);
|
|
30
|
+
|
|
31
|
+
this._M = M;
|
|
32
|
+
|
|
33
|
+
var MT = mjs.transpose(M);
|
|
34
|
+
this._Msymm = mjs.divide(mjs.add(M, MT), 2.0);
|
|
35
|
+
this._Masymm = mjs.subtract(M, this._Msymm);
|
|
36
|
+
|
|
37
|
+
// Diagonalize
|
|
38
|
+
var eigs = mjs.eigs(this._Msymm);
|
|
39
|
+
// Sort by eigenvalue magnitude
|
|
40
|
+
var evecs = mjs.transpose(eigs.vectors._data);
|
|
41
|
+
eigs = _.zip(eigs.values._data, evecs);
|
|
42
|
+
eigs = _.sortBy(eigs, function(x) {
|
|
43
|
+
return x[0];
|
|
44
|
+
});
|
|
45
|
+
eigs = _.unzip(eigs);
|
|
46
|
+
|
|
47
|
+
this._evals = eigs[0];
|
|
48
|
+
|
|
49
|
+
// Make it right-handed
|
|
50
|
+
evecs = eigs[1];
|
|
51
|
+
evecs[2] = mjs.cross(evecs[0], evecs[1]);
|
|
52
|
+
this._evecs = mjs.transpose(evecs);
|
|
53
|
+
|
|
54
|
+
// Isotropy
|
|
55
|
+
this._iso = mjs.mean(this._evals);
|
|
56
|
+
|
|
57
|
+
// Haeberlen order
|
|
58
|
+
var iso = this._iso;
|
|
59
|
+
var haeb = _.zip(_.range(3), this._evals);
|
|
60
|
+
haeb = _.sortBy(haeb, function(x) {
|
|
61
|
+
return Math.abs(x[1] - iso);
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
this._haeb_evals = [
|
|
65
|
+
this._evals[haeb[1][0]],
|
|
66
|
+
this._evals[haeb[0][0]],
|
|
67
|
+
this._evals[haeb[2][0]]
|
|
68
|
+
];
|
|
69
|
+
|
|
70
|
+
this._haeb_evecs = mjs.transpose([
|
|
71
|
+
evecs[haeb[1][0]],
|
|
72
|
+
evecs[haeb[0][0]],
|
|
73
|
+
mjs.cross(evecs[haeb[1][0]], evecs[haeb[0][0]])
|
|
74
|
+
]);
|
|
75
|
+
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
get data() {
|
|
79
|
+
return JSON.parse(JSON.stringify(this._M._data));
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
get symmetric() {
|
|
83
|
+
return JSON.parse(JSON.stringify(this._Msymm._data));
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
get asymmetric() {
|
|
87
|
+
return JSON.parse(JSON.stringify(this._Masymm._data));
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
get eigenvalues() {
|
|
91
|
+
return Array.from(this._evals);
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
get eigenvectors() {
|
|
95
|
+
return JSON.parse(JSON.stringify(this._evecs));
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
get haeberlen_eigenvalues() {
|
|
99
|
+
return Array.from(this._haeb_evals);
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
get haeberlen_eigenvectors() {
|
|
103
|
+
return JSON.parse(JSON.stringify(this._haeb_evecs));
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
get isotropy() {
|
|
107
|
+
return this._iso;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
get anisotropy() {
|
|
111
|
+
return this._haeb_evals[2] - (this._haeb_evals[0] + this._haeb_evals[1]) / 2.0;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
get reduced_anisotropy() {
|
|
115
|
+
return this._haeb_evals[2] - this._iso;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
get asymmetry() {
|
|
119
|
+
var ra = this.reduced_anisotropy;
|
|
120
|
+
return (this._haeb_evals[1] - this._haeb_evals[0]) / ra;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
get span() {
|
|
124
|
+
return this._evals[2] - this._evals[0];
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
get skew() {
|
|
128
|
+
var s = this.span;
|
|
129
|
+
return 3 * (this._evals[1] - this._iso) / s;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
/**
|
|
133
|
+
* Rotate the TensorData by a given basis, either as passive or active
|
|
134
|
+
* transformation. Returns the rotated TensorData (does not modify this in
|
|
135
|
+
* place). Default is passive. The convention is such that for a symmetric
|
|
136
|
+
* tensor,
|
|
137
|
+
*
|
|
138
|
+
* T.rotate(T.eigenvectors)
|
|
139
|
+
*
|
|
140
|
+
* returns the diagonalised tensor.
|
|
141
|
+
*
|
|
142
|
+
* @param {Array | mathjs.Matrix | TensorData} basis Basis to rotate into
|
|
143
|
+
* @param {Boolean} active If true, make it an active transformation (default is false)
|
|
144
|
+
*
|
|
145
|
+
* @return {TensorData} Rotated tensor
|
|
146
|
+
*/
|
|
147
|
+
rotate(basis, active = false) {
|
|
148
|
+
// Rotate the tensor by the given basis of vectors
|
|
149
|
+
if (basis instanceof mjs.Matrix)
|
|
150
|
+
basis = basis._data;
|
|
151
|
+
if (basis instanceof TensorData)
|
|
152
|
+
basis = basis._M._data;
|
|
153
|
+
|
|
154
|
+
var bR = basis;
|
|
155
|
+
var bL = mjs.transpose(basis);
|
|
156
|
+
|
|
157
|
+
if (active) {
|
|
158
|
+
bR = bL;
|
|
159
|
+
bL = basis;
|
|
160
|
+
}
|
|
161
|
+
var rdata = mjs.multiply(bL, this._M._data, bR);
|
|
162
|
+
|
|
163
|
+
return new TensorData(rdata);
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
|
|
167
|
+
/**
|
|
168
|
+
* Convert this TensorData to return a clone that has been converted from
|
|
169
|
+
* atomic units to Hertz, assuming it's an Electric Field Gradient tensor.
|
|
170
|
+
*
|
|
171
|
+
* @param {Number} Q Quadrupolar moment of the given nucleus (barn)
|
|
172
|
+
*
|
|
173
|
+
* @return {TensorData} Converted tensor
|
|
174
|
+
*/
|
|
175
|
+
efgAtomicToHz(Q) {
|
|
176
|
+
|
|
177
|
+
// Clone self, then multiply all the necessary quantities
|
|
178
|
+
var clone = _.clone(this);
|
|
179
|
+
|
|
180
|
+
var k = efg2hz*Q;
|
|
181
|
+
|
|
182
|
+
clone._M = mjs.multiply(this._M, k);
|
|
183
|
+
clone._Msymm = mjs.multiply(this._Msymm, k);
|
|
184
|
+
clone._Masymm = mjs.multiply(this._Masymm, k);
|
|
185
|
+
|
|
186
|
+
clone._iso = this._iso*k;
|
|
187
|
+
|
|
188
|
+
clone._evals = mjs.multiply(this._evals, k);
|
|
189
|
+
clone._haeb_evals = mjs.multiply(this._haeb_evals, k);
|
|
190
|
+
|
|
191
|
+
return clone;
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
/**
|
|
195
|
+
* Convert this TensorData to return a clone that has been converted from
|
|
196
|
+
* atomic units to Hertz, assuming it's an Indirect Spin-spin Coupling
|
|
197
|
+
* tensor.
|
|
198
|
+
*
|
|
199
|
+
* @param {Number} g1 Gyromagnetic ratio of the first atom
|
|
200
|
+
* @param {Number} g2 Gyromagnetic ratio of the second atom
|
|
201
|
+
*
|
|
202
|
+
* @return {TensorData} Converted tensor
|
|
203
|
+
*/
|
|
204
|
+
iscAtomicToHz(g1, g2) {
|
|
205
|
+
|
|
206
|
+
// Clone self, then multiply all the necessary quantities
|
|
207
|
+
var clone = _.clone(this);
|
|
208
|
+
|
|
209
|
+
var k = isc2hz*g1*g2;
|
|
210
|
+
|
|
211
|
+
clone._M = mjs.multiply(this._M, k);
|
|
212
|
+
clone._Msymm = mjs.multiply(this._Msymm, k);
|
|
213
|
+
clone._Masymm = mjs.multiply(this._Masymm, k);
|
|
214
|
+
|
|
215
|
+
clone._iso = this._iso*k;
|
|
216
|
+
|
|
217
|
+
clone._evals = mjs.multiply(this._evals, k);
|
|
218
|
+
clone._haeb_evals = mjs.multiply(this._haeb_evals, k);
|
|
219
|
+
|
|
220
|
+
return clone;
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
export {
|
|
226
|
+
TensorData
|
|
227
|
+
}
|
package/lib/utils.js
ADDED
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* @fileoverview Utility functions
|
|
5
|
+
* @module
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import _ from 'lodash';
|
|
9
|
+
import * as THREE from 'three';
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Compute a full list of indices of all cells for
|
|
13
|
+
* a supercell of given size
|
|
14
|
+
* @param {Array} scell Size of the requested supercell
|
|
15
|
+
*/
|
|
16
|
+
function supercellGrid(scell) {
|
|
17
|
+
var bounds = _.map(scell, function(x) {
|
|
18
|
+
var lb = Math.ceil(-x / 2)+(1-x%2); // This makes it so that for even supercells we skew on the positive side
|
|
19
|
+
if (Object.is(lb, -0)) {
|
|
20
|
+
lb = 0; // Avoids -0
|
|
21
|
+
}
|
|
22
|
+
var ub = Math.ceil(x / 2)+(1-x%2);
|
|
23
|
+
return [lb, ub];
|
|
24
|
+
});
|
|
25
|
+
var grid = [];
|
|
26
|
+
|
|
27
|
+
for (var i = bounds[0][0]; i < bounds[0][1]; ++i) {
|
|
28
|
+
for (var j = bounds[1][0]; j < bounds[1][1]; ++j) {
|
|
29
|
+
for (var k = bounds[2][0]; k < bounds[2][1]; ++k) {
|
|
30
|
+
grid.push([i, j, k]);
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
return grid;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Reduce a tuple of atomic index + i,j,k cell indices to a single integer
|
|
40
|
+
* @param {int} i Atomic index
|
|
41
|
+
* @param {Array} ijk Cell indices
|
|
42
|
+
* @param {Array} scell Supercell size
|
|
43
|
+
* @param {int} n Number of atoms in the model
|
|
44
|
+
*
|
|
45
|
+
* @return {int} Overall index
|
|
46
|
+
*/
|
|
47
|
+
function supercellIndex(i, ijk, scell, n) {
|
|
48
|
+
|
|
49
|
+
ijk = _.map(ijk, function(x, i) {
|
|
50
|
+
return x + Math.floor((scell[i]-1)/2); // Important (depends on the convention in supercellGrid)
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
// If any of these is smaller than 0, we're sure to be out
|
|
54
|
+
if (ijk[0] < 0 || ijk[1] < 0 || ijk[2] < 0) {
|
|
55
|
+
return -1;
|
|
56
|
+
}
|
|
57
|
+
if (ijk[0] >= scell[0] || ijk[1] >= scell[1] || ijk[2] >= scell[2]) {
|
|
58
|
+
return -1;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
var itot = ijk[2] + ijk[1] * scell[2] + ijk[0] * scell[2] * scell[1];
|
|
62
|
+
itot = i + itot*n;
|
|
63
|
+
|
|
64
|
+
return itot;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Turn a unit cell expressed as Array of Arrays into a THREE.Matrix3 object
|
|
69
|
+
* @param {Array} cell Cell in Array form
|
|
70
|
+
*
|
|
71
|
+
* @return {THREE.Matrix3} Cell in THREE.Matrix3 form
|
|
72
|
+
*/
|
|
73
|
+
function cellMatrix3(cell) {
|
|
74
|
+
var lc = cell;
|
|
75
|
+
cell = new THREE.Matrix3();
|
|
76
|
+
cell.set(lc[0][0], lc[1][0], lc[2][0],
|
|
77
|
+
lc[0][1], lc[1][1], lc[2][1],
|
|
78
|
+
lc[0][2], lc[1][2], lc[2][2]);
|
|
79
|
+
|
|
80
|
+
return cell;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/** Add a static variable to a class definition, old style (will become
|
|
84
|
+
* obsolete once the static keyword is widely accepted in ES)
|
|
85
|
+
* @param {Object} cls Class
|
|
86
|
+
* @param {String} name Name of the variable to define
|
|
87
|
+
* @param {any} value Value to assign to it
|
|
88
|
+
*/
|
|
89
|
+
function addStaticVar(cls, name, value) {
|
|
90
|
+
Object.defineProperty(cls, name, {
|
|
91
|
+
value: value,
|
|
92
|
+
writable: false
|
|
93
|
+
});
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
/** Shift a CPK Color to be more distinct (used for isotopes)
|
|
97
|
+
*
|
|
98
|
+
* @param {int} basec Base color to modify. Can be anything accepted
|
|
99
|
+
* by the THREE.Color constructor, but by default
|
|
100
|
+
* we assume it's an hex integer.
|
|
101
|
+
* @param {float} shift Shift to apply. Should range from -1 to 1.
|
|
102
|
+
*
|
|
103
|
+
* @return {int} Shifted color, returned as hex code.
|
|
104
|
+
*
|
|
105
|
+
* */
|
|
106
|
+
function shiftCpkColor(basec, shift=0) {
|
|
107
|
+
let c = new THREE.Color(basec);
|
|
108
|
+
let hsl = {};
|
|
109
|
+
c.getHSL(hsl);
|
|
110
|
+
// Here the goal is to choose a color that's still similar enough
|
|
111
|
+
// to the original, but also contrasts to it.
|
|
112
|
+
// We shift it more in hue if it's not very saturated/bright, and
|
|
113
|
+
// also shift its lightness towards 0.5 and saturation towards 1,
|
|
114
|
+
// so the hue becomes more evident
|
|
115
|
+
|
|
116
|
+
/*
|
|
117
|
+
let f = ((1.0-hsl.s)/2 + Math.abs(hsl.l-0.5))*0.7 + 0.3;
|
|
118
|
+
hsl.h = (hsl.h+shift*f*0.5)%1;
|
|
119
|
+
|
|
120
|
+
f *= 0.4;
|
|
121
|
+
hsl.s = f+(1-f)*hsl.s;
|
|
122
|
+
f *= 0.5;
|
|
123
|
+
hsl.l = f/2.0+(1-f)*hsl.l;
|
|
124
|
+
*/
|
|
125
|
+
|
|
126
|
+
// How close to white/black is the color?
|
|
127
|
+
let bw = Math.abs(hsl.l-0.5)/0.5;
|
|
128
|
+
|
|
129
|
+
if (Math.abs(bw-1) < 1e-2) {
|
|
130
|
+
// By convention we set the hue as blue
|
|
131
|
+
hsl.h = 0.6666;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
// Reduce/increase luminance most for blacks and whites
|
|
135
|
+
hsl.l = (hsl.l-0.5)*(1-0.05*bw)+0.5;
|
|
136
|
+
// Increase saturation most for blacks and whites
|
|
137
|
+
hsl.s = hsl.s + 0.8*bw;
|
|
138
|
+
// Rotate hue least for vivid colors
|
|
139
|
+
hsl.h = (hsl.h+0.1*(0.5+bw)*shift);
|
|
140
|
+
|
|
141
|
+
c.setHSL(hsl.h, hsl.s, hsl.l);
|
|
142
|
+
|
|
143
|
+
return c.getHex();
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
/** Produce a low-collision hash code from a string argument. The algorithm
|
|
147
|
+
* is inspired by Java's .hashCode() method.
|
|
148
|
+
*
|
|
149
|
+
* @param {String} arg The string to hash
|
|
150
|
+
*
|
|
151
|
+
* @return {int} Hash code
|
|
152
|
+
*/
|
|
153
|
+
function hashCode(arg) {
|
|
154
|
+
arg = arg.toString(); // For sanity
|
|
155
|
+
let hash = 0;
|
|
156
|
+
|
|
157
|
+
for (let i = 0; i < arg.length; ++i) {
|
|
158
|
+
let char = arg.charCodeAt(i);
|
|
159
|
+
hash = ((hash<<5)-hash)+char;
|
|
160
|
+
hash = hash & hash; // Convert to 32bit integer
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
return hash;
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
export {
|
|
167
|
+
supercellGrid, supercellIndex, cellMatrix3, addStaticVar, shiftCpkColor, hashCode
|
|
168
|
+
}
|