@ccp-nc/crystvis-js 0.4.13 → 0.5.0

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.
Files changed (141) hide show
  1. package/.eslintrc.json +0 -0
  2. package/.github/workflows/test-mocha.yml +1 -1
  3. package/.vscode/settings.json +1 -2
  4. package/LICENSE +0 -0
  5. package/README.html +0 -0
  6. package/README.md +2 -2
  7. package/demo/index.html +14 -0
  8. package/demo/main.js +12 -0
  9. package/docs/.nojekyll +0 -0
  10. package/docs-tutorials/Events.md +0 -0
  11. package/docs-tutorials/Queries.md +0 -0
  12. package/fonts/OpenSans/OFL.txt +93 -0
  13. package/fonts/OpenSans/OpenSans-Italic-VariableFont_wdth,wght.ttf +0 -0
  14. package/fonts/OpenSans/OpenSans-VariableFont_wdth,wght.ttf +0 -0
  15. package/fonts/OpenSans/README.txt +100 -0
  16. package/fonts/OpenSans/static/OpenSans/OpenSans-Bold.ttf +0 -0
  17. package/fonts/OpenSans/static/OpenSans/OpenSans-BoldItalic.ttf +0 -0
  18. package/fonts/OpenSans/static/OpenSans/OpenSans-ExtraBold.ttf +0 -0
  19. package/fonts/OpenSans/static/OpenSans/OpenSans-ExtraBoldItalic.ttf +0 -0
  20. package/fonts/OpenSans/static/OpenSans/OpenSans-Italic.ttf +0 -0
  21. package/fonts/OpenSans/static/OpenSans/OpenSans-Light.ttf +0 -0
  22. package/fonts/OpenSans/static/OpenSans/OpenSans-LightItalic.ttf +0 -0
  23. package/fonts/OpenSans/static/OpenSans/OpenSans-Medium.ttf +0 -0
  24. package/fonts/OpenSans/static/OpenSans/OpenSans-MediumItalic.ttf +0 -0
  25. package/fonts/OpenSans/static/OpenSans/OpenSans-Regular.ttf +0 -0
  26. package/fonts/OpenSans/static/OpenSans/OpenSans-SemiBold.ttf +0 -0
  27. package/fonts/OpenSans/static/OpenSans/OpenSans-SemiBoldItalic.ttf +0 -0
  28. package/fonts/OpenSans/static/OpenSans_Condensed/OpenSans_Condensed-Bold.ttf +0 -0
  29. package/fonts/OpenSans/static/OpenSans_Condensed/OpenSans_Condensed-BoldItalic.ttf +0 -0
  30. package/fonts/OpenSans/static/OpenSans_Condensed/OpenSans_Condensed-ExtraBold.ttf +0 -0
  31. package/fonts/OpenSans/static/OpenSans_Condensed/OpenSans_Condensed-ExtraBoldItalic.ttf +0 -0
  32. package/fonts/OpenSans/static/OpenSans_Condensed/OpenSans_Condensed-Italic.ttf +0 -0
  33. package/fonts/OpenSans/static/OpenSans_Condensed/OpenSans_Condensed-Light.ttf +0 -0
  34. package/fonts/OpenSans/static/OpenSans_Condensed/OpenSans_Condensed-LightItalic.ttf +0 -0
  35. package/fonts/OpenSans/static/OpenSans_Condensed/OpenSans_Condensed-Medium.ttf +0 -0
  36. package/fonts/OpenSans/static/OpenSans_Condensed/OpenSans_Condensed-MediumItalic.ttf +0 -0
  37. package/fonts/OpenSans/static/OpenSans_Condensed/OpenSans_Condensed-Regular.ttf +0 -0
  38. package/fonts/OpenSans/static/OpenSans_Condensed/OpenSans_Condensed-SemiBold.ttf +0 -0
  39. package/fonts/OpenSans/static/OpenSans_Condensed/OpenSans_Condensed-SemiBoldItalic.ttf +0 -0
  40. package/fonts/OpenSans/static/OpenSans_SemiCondensed/OpenSans_SemiCondensed-Bold.ttf +0 -0
  41. package/fonts/OpenSans/static/OpenSans_SemiCondensed/OpenSans_SemiCondensed-BoldItalic.ttf +0 -0
  42. package/fonts/OpenSans/static/OpenSans_SemiCondensed/OpenSans_SemiCondensed-ExtraBold.ttf +0 -0
  43. package/fonts/OpenSans/static/OpenSans_SemiCondensed/OpenSans_SemiCondensed-ExtraBoldItalic.ttf +0 -0
  44. package/fonts/OpenSans/static/OpenSans_SemiCondensed/OpenSans_SemiCondensed-Italic.ttf +0 -0
  45. package/fonts/OpenSans/static/OpenSans_SemiCondensed/OpenSans_SemiCondensed-Light.ttf +0 -0
  46. package/fonts/OpenSans/static/OpenSans_SemiCondensed/OpenSans_SemiCondensed-LightItalic.ttf +0 -0
  47. package/fonts/OpenSans/static/OpenSans_SemiCondensed/OpenSans_SemiCondensed-Medium.ttf +0 -0
  48. package/fonts/OpenSans/static/OpenSans_SemiCondensed/OpenSans_SemiCondensed-MediumItalic.ttf +0 -0
  49. package/fonts/OpenSans/static/OpenSans_SemiCondensed/OpenSans_SemiCondensed-Regular.ttf +0 -0
  50. package/fonts/OpenSans/static/OpenSans_SemiCondensed/OpenSans_SemiCondensed-SemiBold.ttf +0 -0
  51. package/fonts/OpenSans/static/OpenSans_SemiCondensed/OpenSans_SemiCondensed-SemiBoldItalic.ttf +0 -0
  52. package/fonts/Rubik/OFL.txt +0 -0
  53. package/fonts/Rubik/README.txt +0 -0
  54. package/fonts/Rubik/Rubik-Italic-VariableFont_wght.ttf +0 -0
  55. package/fonts/Rubik/Rubik-VariableFont_wght.ttf +0 -0
  56. package/fonts/Rubik/static/Rubik-Black.ttf +0 -0
  57. package/fonts/Rubik/static/Rubik-BlackItalic.ttf +0 -0
  58. package/fonts/Rubik/static/Rubik-Bold.ttf +0 -0
  59. package/fonts/Rubik/static/Rubik-BoldItalic.ttf +0 -0
  60. package/fonts/Rubik/static/Rubik-ExtraBold.ttf +0 -0
  61. package/fonts/Rubik/static/Rubik-ExtraBoldItalic.ttf +0 -0
  62. package/fonts/Rubik/static/Rubik-Italic.ttf +0 -0
  63. package/fonts/Rubik/static/Rubik-Light.ttf +0 -0
  64. package/fonts/Rubik/static/Rubik-LightItalic.ttf +0 -0
  65. package/fonts/Rubik/static/Rubik-Medium.ttf +0 -0
  66. package/fonts/Rubik/static/Rubik-MediumItalic.ttf +0 -0
  67. package/fonts/Rubik/static/Rubik-Regular.ttf +0 -0
  68. package/fonts/Rubik/static/Rubik-SemiBold.ttf +0 -0
  69. package/fonts/Rubik/static/Rubik-SemiBoldItalic.ttf +0 -0
  70. package/index.html +0 -0
  71. package/index.js +0 -0
  72. package/jsconf.json +0 -0
  73. package/lib/assets/fonts/OpenSans-Medium.fnt +157 -0
  74. package/lib/assets/fonts/OpenSans-Medium.png +0 -0
  75. package/lib/assets/fonts/Rubik-Medium.fnt +141 -89
  76. package/lib/assets/fonts/Rubik-Medium.png +0 -0
  77. package/lib/assets/fonts/bmpfonts.in.js +6 -1
  78. package/lib/assets/fonts/bmpfonts.js +10 -2
  79. package/lib/assets/fonts/font.js +0 -0
  80. package/lib/assets/fonts/index.js +4 -2
  81. package/lib/assets/fonts/threebmfont.js +0 -0
  82. package/lib/data.js +0 -0
  83. package/lib/formats/cell.js +26 -3
  84. package/lib/formats/cif.js +1 -1
  85. package/lib/formats/magres.js +37 -3
  86. package/lib/formats/xyz.js +7 -2
  87. package/lib/loader.js +0 -0
  88. package/lib/model.js +83 -8
  89. package/lib/modelview.js +35 -0
  90. package/lib/nmrdata.js +0 -0
  91. package/lib/primitives/atoms.js +0 -0
  92. package/lib/primitives/cell.js +25 -3
  93. package/lib/primitives/dither.js +0 -0
  94. package/lib/primitives/ellipsoid.js +29 -9
  95. package/lib/primitives/geometries.js +0 -0
  96. package/lib/primitives/isosurface.js +0 -0
  97. package/lib/primitives/shapes.js +0 -0
  98. package/lib/primitives/sprites.js +2 -2
  99. package/lib/query.js +0 -0
  100. package/lib/render.js +107 -5
  101. package/lib/selbox.js +0 -0
  102. package/lib/shaders/aura.frag +0 -0
  103. package/lib/shaders/aura.vert +0 -0
  104. package/lib/shaders/dither.frag +0 -0
  105. package/lib/shaders/dither.vert +0 -0
  106. package/lib/shaders/index.in.js +0 -0
  107. package/lib/shaders/index.js +0 -0
  108. package/lib/shaders/msdf300.frag +0 -0
  109. package/lib/shaders/msdf300.vert +0 -0
  110. package/lib/tensor.js +1 -1
  111. package/lib/utils.js +22 -1
  112. package/lib/visualizer.js +95 -4
  113. package/package.json +18 -18
  114. package/scripts/build-bundle.js +0 -0
  115. package/scripts/build-fonts.js +8 -3
  116. package/scripts/build-resources.js +0 -0
  117. package/scripts/plugins-shim.js +0 -0
  118. package/test/chemdata.js +1 -1
  119. package/test/data/CHA.cif +0 -0
  120. package/test/data/H2O.xyz +0 -0
  121. package/test/data/H2_bound.xyz +0 -0
  122. package/test/data/bohr.cell +11 -0
  123. package/test/data/ethanol.cell +0 -0
  124. package/test/data/example_single.cif +0 -0
  125. package/test/data/frac.cell +0 -0
  126. package/test/data/org.cif +0 -0
  127. package/test/data/pyridine.xyz +1 -1
  128. package/test/data/pyridine_nocell.xyz +13 -0
  129. package/test/data/si8.xyz +0 -0
  130. package/test/data/si8_noisy.xyz +10 -0
  131. package/test/loader.js +22 -1
  132. package/test/model.js +40 -9
  133. package/test/query.js +1 -1
  134. package/test/tensor.js +1 -1
  135. package/test/test-html/examples.js +0 -0
  136. package/test/test-html/index.html +0 -0
  137. package/test/test-html/index.js +35 -5
  138. package/tools/compile_colors.py +0 -0
  139. package/tools/compile_periodic.py +0 -0
  140. package/tools/ptable.json +0 -0
  141. package/tools/test +0 -0
File without changes
@@ -7,8 +7,10 @@ import {
7
7
  import * as Fonts from './bmpfonts.js';
8
8
 
9
9
  // Load the actual fonts
10
- const RubikMedium = new BitmapFont(Fonts.rubikMediumFont, Fonts.rubikMediumTexture);
10
+ // For some reason if I load more than one font at a time, it breaks...
11
+ // const RubikMedium = new BitmapFont(Fonts.rubikMediumFont, Fonts.rubikMediumTexture);
12
+ const OpenSans = new BitmapFont(Fonts.openSansFont, Fonts.openSansTexture);
11
13
 
12
14
  export {
13
- RubikMedium
15
+ OpenSans
14
16
  };
File without changes
package/lib/data.js CHANGED
File without changes
@@ -8,7 +8,7 @@
8
8
  import _ from 'lodash';
9
9
  import {
10
10
  Atoms
11
- } from 'crystcif-parse';
11
+ } from '@ccp-nc/crystcif-parse';
12
12
 
13
13
  function cellBlocks(lines, units={}) {
14
14
  const block_re = /%BLOCK\s+([A-Z_]+)/;
@@ -56,8 +56,14 @@ function load(contents, filename='cell') {
56
56
 
57
57
  // Admissible units
58
58
  const units = {
59
- 'LATTICE_CART': ['ang'],
60
- 'POSITIONS_ABS': ['ang']
59
+ 'LATTICE_CART': ['ang', 'bohr'],
60
+ 'LATTICE_ABC': ['ang', 'bohr'],
61
+ 'POSITIONS_ABS': ['ang', 'bohr'],
62
+ };
63
+ // conversion factors
64
+ const unit_conv = {
65
+ 'ang': 1.0,
66
+ 'bohr': 0.5291772108 // CODATA 2002
61
67
  };
62
68
 
63
69
  // Find blocks
@@ -90,6 +96,17 @@ function load(contents, filename='cell') {
90
96
  let cell = ccart? blocks['LATTICE_CART'].lines : blocks['LATTICE_ABC'].lines;
91
97
  cell = cell.map((l) => (_.trim(l).split(/\s+/).map(parseFloat)));
92
98
 
99
+ // Scale cell by units
100
+ if (ccart) {
101
+ let u = blocks['LATTICE_CART']['units'] || 'ang';
102
+ cell = cell.map((l) => (l.map((x) => (x*unit_conv[u]))));
103
+ }
104
+ else if (cabc) {
105
+ let u = blocks['LATTICE_ABC']['units'] || 'ang';
106
+ // scale just the first row by units
107
+ cell[0] = cell[0].map((x) => (x*unit_conv[u]));
108
+ }
109
+
93
110
  let elems = [];
94
111
  let positions = [];
95
112
 
@@ -101,6 +118,12 @@ function load(contents, filename='cell') {
101
118
  throw Error('Incomplete line in positions block');
102
119
  elems.push(l[0]);
103
120
  positions.push(l.slice(1,4).map(parseFloat));
121
+ // scale by units if in absolute units
122
+ if (pabs) {
123
+ // if units is not defined, assume angstroms
124
+ let u = blocks['POSITIONS_ABS']['units'] || 'ang';
125
+ positions[positions.length-1] = positions[positions.length-1].map((x) => (x*unit_conv[u]));
126
+ }
104
127
  });
105
128
 
106
129
  var a = new Atoms(elems, positions, cell, {}, pfrac);
@@ -6,7 +6,7 @@
6
6
  */
7
7
 
8
8
  import _ from 'lodash';
9
- import { Atoms } from 'crystcif-parse';
9
+ import { Atoms } from '@ccp-nc/crystcif-parse';
10
10
 
11
11
  function load(contents, filename) {
12
12
 
@@ -8,7 +8,7 @@
8
8
  import _ from 'lodash';
9
9
  import {
10
10
  Atoms
11
- } from 'crystcif-parse';
11
+ } from '@ccp-nc/crystcif-parse';
12
12
  import {
13
13
  TensorData
14
14
  } from '../tensor.js';
@@ -50,6 +50,36 @@ function parseNoAtomLine(line, units) {
50
50
  function parseOneAtomLine(line, units, labels) {
51
51
  // Species label + index, then nine numbers
52
52
  let sp = line[0];
53
+ // CASTEP <22.1.1 has a bug where species with in in-species index >99
54
+ // runs into the species label.
55
+ // To handle those cases, we need to check if the species label has
56
+ // an integer >99 at the end, and if so, remove it from the label
57
+ // and add it to the index.
58
+
59
+ // use regex to find any integer at the end of the species label
60
+ let sp_re = /([a-zA-Z]+)([0-9]+)$/;
61
+ let sp_match = sp.match(sp_re);
62
+ if (sp_match) {
63
+ // if the integer is >99 and the line has 10 elements instead of 11,
64
+ // remove it from the label and add it to the index
65
+ let rogue_int = parseInt(sp_match[2]);
66
+ if (rogue_int > 99 && line.length == 10) {
67
+ console.log(`
68
+ Badly formatted .magres file.
69
+ A line has a species label with an integer >99 at the end,
70
+ which suggests a writing-overflow (known bug in CASTEP).
71
+ e.g. 'Fe100' instead of 'Fe 100'.
72
+ The integer has been removed from the label and added to the index.
73
+ `)
74
+
75
+ sp = sp_match[1];
76
+ // insert the rogue integer into
77
+ // the line array at the correct position
78
+ line.splice(1, 0, rogue_int);
79
+ }
80
+ }
81
+
82
+
53
83
  let sp_i = parseInt(line[1]);
54
84
  let i = _.findIndex(labels, function(x) {
55
85
  return (x[0] == sp) && (x[1] == sp_i);
@@ -221,6 +251,11 @@ function load(contents, filename='magres') {
221
251
  }
222
252
  }
223
253
 
254
+ // Reject if we don't have a cell
255
+ if (!cell) {
256
+ throw Error('No unit cell found in Magres file. We only support Magres files with a Lattice block.');
257
+ }
258
+
224
259
  // Read in the atom positions and species
225
260
  let elems = [];
226
261
  let pos = [];
@@ -243,8 +278,7 @@ function load(contents, filename='magres') {
243
278
  elems.push(l[0]);
244
279
  mlabels.push([l[1], parseInt(l[2])]);
245
280
  labels.push(l[1]);
246
-
247
- pos.push(_.map(l.splice(3), function(x) {
281
+ pos.push(_.map(l.slice(3,6), function(x) {
248
282
  return parseFloat(x) * u;
249
283
  }));
250
284
  }
@@ -6,7 +6,7 @@
6
6
  */
7
7
 
8
8
  import _ from 'lodash';
9
- import { Atoms } from 'crystcif-parse';
9
+ import { Atoms } from '@ccp-nc/crystcif-parse';
10
10
 
11
11
  function load(contents, filename='xyz') {
12
12
 
@@ -23,7 +23,7 @@ function load(contents, filename='xyz') {
23
23
  let info = lines[1];
24
24
  // Check if it's extended format
25
25
  let ext = false;
26
- let rext = /([A-Za-z]+)=(([A-Za-z0-9.:]+)|"([\s0-9.]+)")/g;
26
+ let rext = /([A-Za-z]+)=(([A-Za-z0-9.:]+)|"([\s0-9.e-]+)")/g;
27
27
  let m = rext.exec(info);
28
28
  let matches = [];
29
29
  let cell = null;
@@ -108,6 +108,11 @@ function load(contents, filename='xyz') {
108
108
  }
109
109
  }
110
110
 
111
+ // check if we have a cell
112
+ if (cell === null) {
113
+ throw Error('No cell found in XYZ file. Please use the Extended XYZ format.');
114
+ }
115
+
111
116
  let a = new Atoms(elems, pos, cell, info);
112
117
  if (ext) {
113
118
  for (let i = 0; i < arrays.length; ++i) {
package/lib/loader.js CHANGED
File without changes
package/lib/model.js CHANGED
@@ -13,7 +13,7 @@ import {
13
13
 
14
14
  import {
15
15
  Atoms as Atoms
16
- } from 'crystcif-parse';
16
+ } from '@ccp-nc/crystcif-parse';
17
17
 
18
18
  import * as utils from './utils.js';
19
19
  import * as data from './data.js';
@@ -976,9 +976,27 @@ class Model {
976
976
  return c;
977
977
  });
978
978
 
979
+ let has_cif_labels = false;
980
+
979
981
  // Crystallographic labels
980
982
  if ('labels' in this._atoms_base._arrays) {
981
- this._labels = this._atoms_base._arrays['labels'];
983
+ // If any of the labels don't match the element,
984
+ // then we're assuming they're crystallographic (CIF-style) labels
985
+ if (this._atoms_base._arrays['labels'].some((l, i) => {
986
+ return l !== this._elems[i];
987
+ })) {
988
+ // then use them
989
+ has_cif_labels = true;
990
+ this._labels = this._atoms_base._arrays['labels'];
991
+ } else {
992
+ // otherwise, build new ones and
993
+ // throw a warning to user syaing we're doing this
994
+ this._labels = [];
995
+ for (let i = 0; i < this._elems.length; ++i) {
996
+ this._labels.push(this._elems[i] + '_' + (this._species_indices[i]+1));
997
+ }
998
+ console.warn('No crystallographic labels found in CIF file. Building new ones.');
999
+ }
982
1000
  }
983
1001
  else {
984
1002
  // Build them
@@ -988,13 +1006,15 @@ class Model {
988
1006
  }
989
1007
  }
990
1008
 
1009
+ this._has_cif_labels = has_cif_labels; // defaults to false
991
1010
 
992
1011
  if (this._periodic) {
993
1012
  // R matrix: indispensable for calculations of periodic distances
994
1013
  this._r_matrix = mjs.multiply(this._cell, mjs.transpose(this._cell));
995
1014
  var ediag = mjs.eigs(this._r_matrix);
996
- // Sort by eigenvalue
997
- ediag = _.zip(ediag.values, ediag.vectors);
1015
+ // Sort by eigenvalue
1016
+ var evecs = ediag.eigenvectors.map(e => e.vector);
1017
+ ediag = _.zip(ediag.values, evecs);
998
1018
  ediag = _.sortBy(ediag, function(x) {
999
1019
  return x[0];
1000
1020
  });
@@ -1003,7 +1023,7 @@ class Model {
1003
1023
  this._r_diag = {
1004
1024
  values: ediag[0],
1005
1025
  vectors: ediag[1],
1006
- }
1026
+ };
1007
1027
 
1008
1028
  this._supercell = supercell; // Default
1009
1029
  this._supercell_grid = utils.supercellGrid(supercell);
@@ -1021,7 +1041,11 @@ class Model {
1021
1041
 
1022
1042
  initMolecules(atoms, parameters.supercell);
1023
1043
 
1024
- if (parameters.molecularCrystal) {
1044
+ // if parameters.molecularCrystal, is null, we need to check if the atoms
1045
+ // contains organic molecules -- i.e. if there is at least one C-H bond
1046
+ if (parameters.molecularCrystal || (parameters.molecularCrystal === null &&
1047
+ this._queryCHBond())) {
1048
+ this._molecularCrystal = true;
1025
1049
  atoms = _.cloneDeep(atoms);
1026
1050
  var pos = this.positions;
1027
1051
  for (let i = 0; i < this.length; ++i) {
@@ -1248,7 +1272,7 @@ class Model {
1248
1272
  if (this.periodic) {
1249
1273
  // Create axes and box
1250
1274
  if (!this._cartesian_box) {
1251
- this._cartesian_box = new r.Primitives.BoxMesh(this.cell);
1275
+ this._cartesian_box = new r.Primitives.BoxMesh(this.cell, {color:r.theme.cell_line_color});
1252
1276
  }
1253
1277
  if (!this._cartesian_axes) {
1254
1278
  this._cartesian_axes = new r.Primitives.AxesMesh(this.cell, {
@@ -1341,7 +1365,7 @@ class Model {
1341
1365
  color: parameters.color,
1342
1366
  fixScale: true,
1343
1367
  faceCamera: true,
1344
- height: LABEL_HEIGHT,
1368
+ height: parameters.height || LABEL_HEIGHT,
1345
1369
  shift: [LABEL_HEIGHT, 0, 0],
1346
1370
  onOverlay: parameters.onOverlay
1347
1371
  });
@@ -1492,6 +1516,40 @@ class Model {
1492
1516
  }
1493
1517
  }
1494
1518
 
1519
+ /**
1520
+ * Check if any C-H bonds are present
1521
+ * @return {bool} Whether any C-H bonds are present
1522
+ * @private
1523
+ */
1524
+ _queryCHBond() {
1525
+ // make sure bondmat is present
1526
+ if (!this._bondmat) {
1527
+ this._computeBonds();
1528
+ }
1529
+
1530
+ var symbols = this._atoms_base.get_chemical_symbols();
1531
+ var bondmat = this._bondmat;
1532
+ var n = symbols.length;
1533
+ for (var i = 0; i < n; i++) {
1534
+ var bonds = bondmat[i];
1535
+ var a = symbols[i];
1536
+ if (a == 'C') {
1537
+ // loop over bonds and check if any are H
1538
+ for (var j = 0; j < n; j++) {
1539
+ // if bonds[j] is not an empty array
1540
+ if (bonds[j].length) {
1541
+ if (symbols[j] == 'H') {
1542
+ return true;
1543
+ }
1544
+ }
1545
+ }
1546
+ }
1547
+ }
1548
+ return false;
1549
+ }
1550
+
1551
+
1552
+
1495
1553
  /**
1496
1554
  * Compute the molecules within the model. For internal use
1497
1555
  * @private
@@ -1804,6 +1862,23 @@ class Model {
1804
1862
  return this._queryIndices(indices);
1805
1863
  }
1806
1864
 
1865
+ /**
1866
+ * @private
1867
+ */
1868
+ _queryLabels(labels) {
1869
+ if (_.isString(labels)) {
1870
+ labels = [labels]; // A single label
1871
+ }
1872
+ var indices = _.reduce(this._labels, function(inds, s, i) {
1873
+ if (labels.indexOf(s) > -1) {
1874
+ inds.push(i);
1875
+ }
1876
+ return inds;
1877
+ }, []);
1878
+
1879
+ return this._queryIndices(indices);
1880
+ }
1881
+
1807
1882
  /**
1808
1883
  * @private
1809
1884
  */
package/lib/modelview.js CHANGED
@@ -169,6 +169,34 @@ class ModelView {
169
169
  return new ModelView(this._model, indices);
170
170
  }
171
171
 
172
+ /**
173
+ * Remove all atoms in mview from the current view
174
+ */
175
+ remove(mview) {
176
+ if (this._model != mview._model)
177
+ throw 'The two ModelViews do not refer to the same Model';
178
+ return new ModelView(this._model,
179
+ _.differenceWith(this._indices, mview._indices));
180
+ }
181
+
182
+ /**
183
+ * Unique atoms in the current view (based on site labels)
184
+ */
185
+ uniqueSites() {
186
+ // all labels:
187
+ var labels = this._images.map(function(a) { return a.crystLabel; });
188
+ var allIndices = this._indices;
189
+
190
+ // unique labels:
191
+ var ulabels = _.uniq(labels);
192
+ // indices of unique labels:
193
+ var uindices = ulabels.map(function(l) { return allIndices[labels.indexOf(l)]; });
194
+ // sort the uindices:
195
+ uindices.sort(function(a, b) { return a - b; });
196
+ // return the unique atoms:
197
+ return new ModelView(this._model, uindices);
198
+ }
199
+
172
200
  /**
173
201
  * Internal function used to turn a single value, array of values, or
174
202
  * function into an array of values
@@ -220,6 +248,13 @@ class ModelView {
220
248
  return this;
221
249
  }
222
250
 
251
+ /**
252
+ * Get sorted set of unique elements in the ModelView
253
+ */
254
+ get elements() {
255
+ return _.uniq(this.map(a => a.element).sort());
256
+ }
257
+
223
258
  /**
224
259
  * Add labels to the atom images in this ModelView
225
260
  *
package/lib/nmrdata.js CHANGED
File without changes
File without changes
@@ -8,6 +8,9 @@ import _ from 'lodash';
8
8
  import * as THREE from 'three';
9
9
  import { Vector3 } from 'three';
10
10
  import { cellMatrix3 } from '../utils.js';
11
+ import { TextSprite } from './sprites.js';
12
+
13
+ const LABEL_HEIGHT = 0.04; // Height of the label
11
14
 
12
15
  // Cell box
13
16
  class BoxMesh extends THREE.LineSegments {
@@ -67,19 +70,21 @@ class AxesMesh extends THREE.Group {
67
70
  *
68
71
  * @param {Array} lattice Lattice parameters for the unit cell
69
72
  * @param {Object} parameters Options:
70
- * linewidth
73
+ * linewidth (NB: on most platforms linewidth will always be 1 regardless of the set value. This is a known issue with three.js)
71
74
  * xColor
72
75
  * yColor
73
76
  * zColor
77
+ * labels: array of strings for the labels. Defaults to null, which means no labels
74
78
  *
75
79
  */
76
80
  constructor(lattice, parameters = {}) {
77
81
 
78
82
  var defaults = {
79
- linewidth: 1.2,
83
+ linewidth: 1.2, // this often is effectively 1.0. See: https://threejs.org/docs/?q=lineba#api/en/materials/LineBasicMaterial.linewidth
80
84
  xColor: 0xff0000,
81
85
  yColor: 0x00ff00,
82
- zColor: 0x0000ff
86
+ zColor: 0x0000ff,
87
+ labels: null
83
88
  };
84
89
 
85
90
  parameters = _.merge(defaults, parameters);
@@ -112,6 +117,23 @@ class AxesMesh extends THREE.Group {
112
117
  var arr = new THREE.ArrowHelper(dir, origin, l, colors[i]);
113
118
  arr.line.material.linewidth = parameters.linewidth;
114
119
  this.add(arr);
120
+
121
+ if (parameters.labels) {
122
+ // assert parameters.labels.length == 3
123
+ var label = parameters.labels[i];
124
+ var labelPos = dir.clone().multiplyScalar(l * 1.1);
125
+ var text = new TextSprite(label, {
126
+ position: labelPos,
127
+ color: colors[i],
128
+ height: LABEL_HEIGHT,
129
+ faceCamera: true,
130
+ fixScale: true,
131
+ shift: [0.0,0,0.0],
132
+ });
133
+ this.add(text);
134
+ }
135
+
136
+
115
137
  }
116
138
  }
117
139
 
File without changes
@@ -31,6 +31,7 @@ class EllipsoidMesh extends THREE.Mesh {
31
31
  color: 0xff0000,
32
32
  opacity: 0.5,
33
33
  opacityMode: EllipsoidMesh.DITHER,
34
+ showEllipsoid: true,
34
35
  showCircles: true,
35
36
  showAxes: true,
36
37
  scalingFactor: 1.0
@@ -86,21 +87,36 @@ class EllipsoidMesh extends THREE.Mesh {
86
87
  if (parameters.showAxes) {
87
88
 
88
89
  let matline = new THREE.LineBasicMaterial({
89
- color: new THREE.Color(c),
90
+ color: new THREE.Color(0xff0000),
90
91
  });
91
92
 
92
93
  let geoline = new THREE.BufferGeometry().setFromPoints([new THREE.Vector3(-1, 0, 0),
93
94
  new THREE.Vector3(1, 0, 0)
94
95
  ]);
96
+
97
+ // change the color of the x axis
98
+ matline = new THREE.LineBasicMaterial({
99
+ color: new THREE.Color(0xff0000),
100
+ });
101
+ let xseg = new THREE.LineSegments(geoline, matline);
102
+ this.add(xseg);
95
103
 
96
- let cseg = new THREE.Line(geoline, matline);
97
- this.add(cseg);
98
- cseg = new THREE.Line(geoline, matline);
99
- cseg.rotateZ(Math.PI / 2.0);
100
- this.add(cseg);
101
- cseg = new THREE.Line(geoline, matline);
102
- cseg.rotateY(Math.PI / 2.0);
103
- this.add(cseg);
104
+ // change the color of the y axis
105
+ matline = new THREE.LineBasicMaterial({
106
+ color: new THREE.Color(0x00ff00),
107
+ });
108
+ let yseg = new THREE.LineSegments(geoline, matline);
109
+ yseg.rotateZ(Math.PI / 2.0);
110
+ this.add(yseg);
111
+
112
+ // change the color of the z axis
113
+ matline = new THREE.LineBasicMaterial({
114
+ color: new THREE.Color(0x0000ff),
115
+ });
116
+ // matline.color = new THREE.Color(0x0000ff);
117
+ let zseg = new THREE.LineSegments(geoline, matline);
118
+ zseg.rotateY(Math.PI / 2.0);
119
+ this.add(zseg);
104
120
  }
105
121
 
106
122
  let c0 = parameters.center;
@@ -115,6 +131,10 @@ class EllipsoidMesh extends THREE.Mesh {
115
131
  this.eigenvalues = parameters.eigenvalues;
116
132
  this.eigenvectors = parameters.eigenvectors;
117
133
 
134
+ // set material to be invisible if showEllipsoid is false
135
+ if (!parameters.showEllipsoid) {
136
+ material.visible = false;
137
+ }
118
138
  this.renderOrder = 0.5;
119
139
  }
120
140
 
File without changes
File without changes
File without changes
@@ -7,7 +7,7 @@
7
7
  import _ from 'lodash';
8
8
  import * as THREE from 'three';
9
9
  import {
10
- RubikMedium
10
+ OpenSans
11
11
  } from '../assets/fonts/index.js';
12
12
 
13
13
 
@@ -85,7 +85,7 @@ class TextSprite extends THREE.Mesh {
85
85
 
86
86
  var defaults = {
87
87
  position: [0, 0, 0],
88
- font: RubikMedium,
88
+ font: OpenSans,
89
89
  color: 0xffffff,
90
90
  opacity: 1.0,
91
91
  height: 1.0,
package/lib/query.js CHANGED
File without changes