@ccp-nc/crystvis-js 0.7.0 → 0.7.2

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 (44) hide show
  1. package/lib/render.js +41 -15
  2. package/package.json +3 -2
  3. package/test/render.js +168 -0
  4. package/test/setup-dom.cjs +65 -3
  5. package/docs/data/search.json +0 -1
  6. package/docs/fonts/Inconsolata-Regular.ttf +0 -0
  7. package/docs/fonts/OpenSans-Regular.ttf +0 -0
  8. package/docs/fonts/WorkSans-Bold.ttf +0 -0
  9. package/docs/index.html +0 -59
  10. package/docs/lib_model.module_js-AtomImage.html +0 -3
  11. package/docs/lib_model.module_js-BondImage.html +0 -3
  12. package/docs/lib_model.module_js-Model.html +0 -3
  13. package/docs/lib_model.module_js.html +0 -3
  14. package/docs/lib_modelview.module_js-ModelView.html +0 -12
  15. package/docs/lib_modelview.module_js.html +0 -3
  16. package/docs/lib_visualizer.module_js-CrystVis.html +0 -3
  17. package/docs/lib_visualizer.module_js.html +0 -3
  18. package/docs/model.js.html +0 -2191
  19. package/docs/modelview.js.html +0 -473
  20. package/docs/scripts/core.js +0 -726
  21. package/docs/scripts/core.min.js +0 -23
  22. package/docs/scripts/resize.js +0 -90
  23. package/docs/scripts/search.js +0 -265
  24. package/docs/scripts/search.min.js +0 -6
  25. package/docs/scripts/third-party/Apache-License-2.0.txt +0 -202
  26. package/docs/scripts/third-party/fuse.js +0 -9
  27. package/docs/scripts/third-party/hljs-line-num-original.js +0 -369
  28. package/docs/scripts/third-party/hljs-line-num.js +0 -1
  29. package/docs/scripts/third-party/hljs-original.js +0 -5171
  30. package/docs/scripts/third-party/hljs.js +0 -1
  31. package/docs/scripts/third-party/popper.js +0 -5
  32. package/docs/scripts/third-party/tippy.js +0 -1
  33. package/docs/scripts/third-party/tocbot.js +0 -672
  34. package/docs/scripts/third-party/tocbot.min.js +0 -1
  35. package/docs/styles/clean-jsdoc-theme-base.css +0 -1159
  36. package/docs/styles/clean-jsdoc-theme-dark.css +0 -412
  37. package/docs/styles/clean-jsdoc-theme-light.css +0 -482
  38. package/docs/styles/clean-jsdoc-theme-scrollbar.css +0 -30
  39. package/docs/styles/clean-jsdoc-theme-without-scrollbar.min.css +0 -1
  40. package/docs/styles/clean-jsdoc-theme.min.css +0 -1
  41. package/docs/tutorial-Events.html +0 -13
  42. package/docs/tutorial-Queries.html +0 -16
  43. package/docs/tutorial-ThreejsMigration.html +0 -25
  44. package/docs/visualizer.js.html +0 -810
@@ -1,2191 +0,0 @@
1
- <!DOCTYPE html><html lang="en" style="font-size:16px"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1"><title>Source: model.js</title><!--[if lt IE 9]>
2
- <script src="//html5shiv.googlecode.com/svn/trunk/html5.js"></script>
3
- <![endif]--><script src="scripts/third-party/hljs.js" defer="defer"></script><script src="scripts/third-party/hljs-line-num.js" defer="defer"></script><script src="scripts/third-party/popper.js" defer="defer"></script><script src="scripts/third-party/tippy.js" defer="defer"></script><script src="scripts/third-party/tocbot.min.js"></script><script>var baseURL="/",locationPathname="";baseURL=(locationPathname=document.location.pathname).substr(0,locationPathname.lastIndexOf("/")+1)</script><link rel="stylesheet" href="styles/clean-jsdoc-theme.min.css"><svg aria-hidden="true" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" style="display:none"><defs><symbol id="copy-icon" viewbox="0 0 488.3 488.3"><g><path d="M314.25,85.4h-227c-21.3,0-38.6,17.3-38.6,38.6v325.7c0,21.3,17.3,38.6,38.6,38.6h227c21.3,0,38.6-17.3,38.6-38.6V124 C352.75,102.7,335.45,85.4,314.25,85.4z M325.75,449.6c0,6.4-5.2,11.6-11.6,11.6h-227c-6.4,0-11.6-5.2-11.6-11.6V124 c0-6.4,5.2-11.6,11.6-11.6h227c6.4,0,11.6,5.2,11.6,11.6V449.6z"/><path d="M401.05,0h-227c-21.3,0-38.6,17.3-38.6,38.6c0,7.5,6,13.5,13.5,13.5s13.5-6,13.5-13.5c0-6.4,5.2-11.6,11.6-11.6h227 c6.4,0,11.6,5.2,11.6,11.6v325.7c0,6.4-5.2,11.6-11.6,11.6c-7.5,0-13.5,6-13.5,13.5s6,13.5,13.5,13.5c21.3,0,38.6-17.3,38.6-38.6 V38.6C439.65,17.3,422.35,0,401.05,0z"/></g></symbol><symbol id="search-icon" viewBox="0 0 512 512"><g><g><path d="M225.474,0C101.151,0,0,101.151,0,225.474c0,124.33,101.151,225.474,225.474,225.474 c124.33,0,225.474-101.144,225.474-225.474C450.948,101.151,349.804,0,225.474,0z M225.474,409.323 c-101.373,0-183.848-82.475-183.848-183.848S124.101,41.626,225.474,41.626s183.848,82.475,183.848,183.848 S326.847,409.323,225.474,409.323z"/></g></g><g><g><path d="M505.902,476.472L386.574,357.144c-8.131-8.131-21.299-8.131-29.43,0c-8.131,8.124-8.131,21.306,0,29.43l119.328,119.328 c4.065,4.065,9.387,6.098,14.715,6.098c5.321,0,10.649-2.033,14.715-6.098C514.033,497.778,514.033,484.596,505.902,476.472z"/></g></g></symbol><symbol id="font-size-icon" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0z"/><path d="M11.246 15H4.754l-2 5H.6L7 4h2l6.4 16h-2.154l-2-5zm-.8-2L8 6.885 5.554 13h4.892zM21 12.535V12h2v8h-2v-.535a4 4 0 1 1 0-6.93zM19 18a2 2 0 1 0 0-4 2 2 0 0 0 0 4z"/></symbol><symbol id="add-icon" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0z"/><path d="M11 11V5h2v6h6v2h-6v6h-2v-6H5v-2z"/></symbol><symbol id="minus-icon" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0z"/><path d="M5 11h14v2H5z"/></symbol><symbol id="dark-theme-icon" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0z"/><path d="M10 7a7 7 0 0 0 12 4.9v.1c0 5.523-4.477 10-10 10S2 17.523 2 12 6.477 2 12 2h.1A6.979 6.979 0 0 0 10 7zm-6 5a8 8 0 0 0 15.062 3.762A9 9 0 0 1 8.238 4.938 7.999 7.999 0 0 0 4 12z"/></symbol><symbol id="light-theme-icon" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0z"/><path d="M12 18a6 6 0 1 1 0-12 6 6 0 0 1 0 12zm0-2a4 4 0 1 0 0-8 4 4 0 0 0 0 8zM11 1h2v3h-2V1zm0 19h2v3h-2v-3zM3.515 4.929l1.414-1.414L7.05 5.636 5.636 7.05 3.515 4.93zM16.95 18.364l1.414-1.414 2.121 2.121-1.414 1.414-2.121-2.121zm2.121-14.85l1.414 1.415-2.121 2.121-1.414-1.414 2.121-2.121zM5.636 16.95l1.414 1.414-2.121 2.121-1.414-1.414 2.121-2.121zM23 11v2h-3v-2h3zM4 11v2H1v-2h3z"/></symbol><symbol id="reset-icon" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0z"/><path d="M18.537 19.567A9.961 9.961 0 0 1 12 22C6.477 22 2 17.523 2 12S6.477 2 12 2s10 4.477 10 10c0 2.136-.67 4.116-1.81 5.74L17 12h3a8 8 0 1 0-2.46 5.772l.997 1.795z"/></symbol><symbol id="down-icon" viewBox="0 0 16 16"><path fill-rule="evenodd" clip-rule="evenodd" d="M12.7803 6.21967C13.0732 6.51256 13.0732 6.98744 12.7803 7.28033L8.53033 11.5303C8.23744 11.8232 7.76256 11.8232 7.46967 11.5303L3.21967 7.28033C2.92678 6.98744 2.92678 6.51256 3.21967 6.21967C3.51256 5.92678 3.98744 5.92678 4.28033 6.21967L8 9.93934L11.7197 6.21967C12.0126 5.92678 12.4874 5.92678 12.7803 6.21967Z"></path></symbol><symbol id="codepen-icon" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0z"/><path d="M16.5 13.202L13 15.535v3.596L19.197 15 16.5 13.202zM14.697 12L12 10.202 9.303 12 12 13.798 14.697 12zM20 10.869L18.303 12 20 13.131V10.87zM19.197 9L13 4.869v3.596l3.5 2.333L19.197 9zM7.5 10.798L11 8.465V4.869L4.803 9 7.5 10.798zM4.803 15L11 19.131v-3.596l-3.5-2.333L4.803 15zM4 13.131L5.697 12 4 10.869v2.262zM2 9a1 1 0 0 1 .445-.832l9-6a1 1 0 0 1 1.11 0l9 6A1 1 0 0 1 22 9v6a1 1 0 0 1-.445.832l-9 6a1 1 0 0 1-1.11 0l-9-6A1 1 0 0 1 2 15V9z"/></symbol><symbol id="close-icon" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0z"/><path d="M12 10.586l4.95-4.95 1.414 1.414-4.95 4.95 4.95 4.95-1.414 1.414-4.95-4.95-4.95 4.95-1.414-1.414 4.95-4.95-4.95-4.95L7.05 5.636z"/></symbol><symbol id="menu-icon" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0z"/><path d="M3 4h18v2H3V4zm0 7h18v2H3v-2zm0 7h18v2H3v-2z"/></symbol></defs></svg></head><body data-theme="dark"><div class="sidebar-container"><div class="sidebar" id="sidebar"><div class="sidebar-items-container"><div class="sidebar-section-title with-arrow" data-isopen="false" id="sidebar-modules"><div>Modules</div><svg><use xlink:href="#down-icon"></use></svg></div><div class="sidebar-section-children-container"><div class="sidebar-section-children"><a href="lib_model.module_js.html">lib/model.js</a></div><div class="sidebar-section-children"><a href="lib_modelview.module_js.html">lib/modelview.js</a></div><div class="sidebar-section-children"><a href="lib_visualizer.module_js.html">lib/visualizer.js</a></div></div><div class="sidebar-section-title with-arrow" data-isopen="false" id="sidebar-classes"><div>Classes</div><svg><use xlink:href="#down-icon"></use></svg></div><div class="sidebar-section-children-container"><div class="sidebar-section-children"><a href="lib_model.module_js-AtomImage.html">AtomImage</a></div><div class="sidebar-section-children"><a href="lib_model.module_js-BondImage.html">BondImage</a></div><div class="sidebar-section-children"><a href="lib_model.module_js-Model.html">Model</a></div><div class="sidebar-section-children"><a href="lib_modelview.module_js-ModelView.html">ModelView</a></div><div class="sidebar-section-children"><a href="lib_visualizer.module_js-CrystVis.html">CrystVis</a></div></div><div class="sidebar-section-title with-arrow" data-isopen="false" id="sidebar-tutorials"><div>Tutorials</div><svg><use xlink:href="#down-icon"></use></svg></div><div class="sidebar-section-children-container"><div class="sidebar-section-children"><a href="tutorial-Events.html">Events</a></div><div class="sidebar-section-children"><a href="tutorial-Queries.html">Queries</a></div><div class="sidebar-section-children"><a href="tutorial-ThreejsMigration.html">ThreejsMigration</a></div></div></div></div></div><div class="navbar-container" id="VuAckcnZhf"><nav class="navbar"><div class="navbar-left-items"></div><div class="navbar-right-items"><div class="navbar-right-item"><button class="icon-button search-button" aria-label="open-search"><svg><use xlink:href="#search-icon"></use></svg></button></div><div class="navbar-right-item"><button class="icon-button theme-toggle" aria-label="toggle-theme"><svg><use class="theme-svg-use" xlink:href="#light-theme-icon"></use></svg></button></div><div class="navbar-right-item"><button class="icon-button font-size" aria-label="change-font-size"><svg><use xlink:href="#font-size-icon"></use></svg></button></div></div><nav></nav></nav></div><div class="toc-container"><div class="toc-content"><span class="bold">On this page</span><div id="eed4d2a0bfd64539bb9df78095dec881"></div></div></div><div class="body-wrapper"><div class="main-content"><div class="main-wrapper"><section id="source-page" class="source-page"><header><h1 id="title" class="has-anchor">model.js</h1></header><article><pre class="prettyprint source lang-js"><code>'use strict';
4
-
5
- /**
6
- * @fileoverview Class holding the atomic models to be plotted
7
- * @module
8
- */
9
-
10
- import _ from 'lodash';
11
- import * as mjs from 'mathjs';
12
- import {
13
- PeriodicTable as PeriodicTable
14
- } from 'mendeleev';
15
-
16
- import {
17
- Atoms as Atoms
18
- } from '@ccp-nc/crystcif-parse';
19
-
20
- import * as utils from './utils.js';
21
- import * as data from './data.js';
22
- import {
23
- QueryParser as QueryParser
24
- } from './query.js';
25
- import {
26
- ModelView as ModelView
27
- } from './modelview.js';
28
-
29
-
30
- const LABEL_HEIGHT = 0.04; // For now fixed, just a value that works
31
-
32
-
33
- /** An 'image' of a single atom from a model. This represents a specific periodic copy of that atom (if applicable). */
34
- class AtomImage {
35
-
36
- /**
37
- * @class
38
- * @param {Model} model The model from which the image is from
39
- * @param {int} index Index of the atom in the model
40
- * @param {Array} ijk Indices of the cell in which the image is located
41
- */
42
- constructor(model, index, ijk) {
43
-
44
- this._model = model;
45
- this._index = index;
46
- this._ijk = ijk || [0, 0, 0];
47
-
48
- // String ID
49
- this._id = this._index + '_' + _.join(this._ijk, '_');
50
- // Integer index
51
- this._img_index = utils.supercellIndex(index, this._ijk,
52
- model.supercell, model.length);
53
-
54
- this._xyz0 = model._positions[index];
55
-
56
- this._bondsFrom = []; // BondImages of bonds for which this is atom1
57
- this._bondsTo = []; // BondImages of bonds for which this is atom2
58
-
59
- if (!model.periodic) {
60
- this._fxyz0 = null;
61
- this._fxyz = null;
62
- this._xyz = this._xyz0;
63
- } else {
64
- this._fxyz0 = model._scaled_positions[index];
65
- this._fxyz = [this._fxyz0[0] + ijk[0],
66
- this._fxyz0[1] + ijk[1],
67
- this._fxyz0[2] + ijk[2]
68
- ];
69
- this._xyz = mjs.multiply(this._fxyz, model._cell);
70
- }
71
-
72
- this._isotope = null; // By default look up the model
73
-
74
- // Visual properties
75
- this._visible = false;
76
- this._color = this.cpkColor;
77
- this._uses_cpk = true;
78
- this._base_radius = this.vdwRadius / 4.0;
79
- this._scale = 1.0;
80
- this._opacity = 1.0;
81
- this._highlighted = false;
82
-
83
- this._mesh = null; // Will be created when first requested
84
- this._aura = null;
85
-
86
- this._labels = {};
87
- this._ellipsoids = {};
88
- }
89
-
90
- /**
91
- * Model this atom belongs to
92
- * @readonly
93
- * @type {Model}
94
- */
95
- get model() {
96
- return this._model;
97
- }
98
-
99
- /**
100
- * Renderer used by this atom
101
- * @readonly
102
- * @type {Renderer}
103
- */
104
- get renderer() {
105
- var m = this.model;
106
-
107
- if (m) {
108
- return m._renderer;
109
- }
110
-
111
- return null;
112
- }
113
-
114
- /**
115
- * Index of the atom
116
- * @readonly
117
- * @type {int}
118
- */
119
- get index() {
120
- return this._index;
121
- }
122
-
123
- /**
124
- * String ID of the image
125
- * @readonly
126
- * @type {String}
127
- */
128
- get id() {
129
- return this._id;
130
- }
131
-
132
- /**
133
- * Index of this image
134
- * @readonly
135
- * @type {int}
136
- */
137
- get imgIndex() {
138
- return this._img_index;
139
- }
140
-
141
- /**
142
- * Index of the species of this atom
143
- * @readonly
144
- * @type {int}
145
- */
146
- get speciesIndex() {
147
- return this._model._species_indices[this._index];
148
- }
149
-
150
- /**
151
- * Symbol of this atom's element
152
- * @readonly
153
- * @type {String}
154
- */
155
- get element() {
156
- return this._model._elems[this._index];
157
- }
158
-
159
- /**
160
- * Crystal site label of this atom
161
- * @readonly
162
- * @type {String}
163
- */
164
- get crystLabel() {
165
- return this._model._labels[this._index];
166
- }
167
-
168
- /**
169
- * Periodic table information for this atom's element
170
- * @readonly
171
- * @type {Object}
172
- */
173
- get elementData() {
174
- return data.getElementData(this.element);
175
- }
176
-
177
- /**
178
- * Information for this atom's isotope
179
- * @readonly
180
- * @type {Object}
181
- */
182
- get isotopeData() {
183
- let idata = this._isotope;
184
- if (idata === null)
185
- idata = this._model._isotopes[this._index];
186
- return idata;
187
- }
188
-
189
- /**
190
- * Atomic mass of this atom's isotope
191
- * @type {int}
192
- */
193
- get isotope() {
194
- return this.isotopeData.A;
195
- }
196
-
197
- set isotope(A) {
198
- this._isotope = data.getIsotopeData(this.element, A);
199
- if (this._isotope === null)
200
- throw Error('Isotope does not exist for this element');
201
- // Reset color
202
- if (this._uses_cpk) {
203
- this.color = null;
204
- }
205
- }
206
-
207
- /**
208
- * Atomic mass of the global isotope set as default for this atom's species
209
- * @type {int}
210
- */
211
- set isotopeGlobal(A) {
212
- // Set the isotope for this atom in the model
213
- let iso = data.getIsotopeData(this.element, A);
214
- if (iso === null)
215
- throw Error('Isotope does not exist for this element');
216
- this._model._isotopes[this._index] = iso;
217
- // Reset color
218
- if (this._uses_cpk) {
219
- this.color = null;
220
- }
221
- }
222
-
223
- /**
224
- * Atomic number of element
225
- * @readonly
226
- * @type {int}
227
- */
228
- get number() {
229
- var el = PeriodicTable.getElement(this.element);
230
- return (el ? el.number : 0);
231
- }
232
-
233
- /**
234
- * Hex integer code of the conventional CPK color used for this element
235
- * (altered in case of non-standard isotopes)
236
- * @readonly
237
- * @type {int}
238
- */
239
- get cpkColor() {
240
- return data.getCpkColor(this.element, this.isotope);
241
- }
242
-
243
- /**
244
- * Van dew Waals radius for this element
245
- * @readonly
246
- * @type {float}
247
- */
248
- get vdwRadius() {
249
- return data.getVdwRadius(this.element);
250
- }
251
-
252
- /**
253
- * Bonds from this atom
254
- * @readonly
255
- * @type {BondImage[]}
256
- */
257
- get bondsFrom() {
258
- return Array.from(this._bondsFrom);
259
- }
260
-
261
- /**
262
- * Bonds to this atom
263
- * @readonly
264
- * @type {BondImage[]}
265
- */
266
- get bondsTo() {
267
- return Array.from(this._bondsTo);
268
- }
269
-
270
- /**
271
- * All bonds connected to this atom
272
- * @readonly
273
- * @type {BondImage[]}
274
- */
275
- get bonds() {
276
- return _.concat(this._bondsFrom, this._bondsTo);
277
- }
278
-
279
- /**
280
- * All atoms bonded to this atom
281
- * @readonly
282
- * @type {AtomImage[]}
283
- */
284
- get bondedAtoms() {
285
- return _.concat(_.map(this._bondsFrom, function(b) {
286
- return b.atom2;
287
- }),
288
- _.map(this._bondsTo, function(b) {
289
- return b.atom1;
290
- }));
291
- }
292
-
293
- /**
294
- * Cell indices of this atom image
295
- * @readonly
296
- * @type {int[]}
297
- */
298
- get ijk() {
299
- return Array.from(this._ijk);
300
- }
301
-
302
- /**
303
- * Position of this atom's original
304
- * @readonly
305
- * @type {float[]}
306
- */
307
- get xyz0() {
308
- return Array.from(this._xyz0);
309
- }
310
-
311
- /**
312
- * Position of this atom image
313
- * @readonly
314
- * @type {float[]}
315
- */
316
- get xyz() {
317
- return Array.from(this._xyz);
318
- }
319
-
320
- /**
321
- * Fractional coordinates of this atom's original
322
- * @readonly
323
- * @type {float[]}
324
- */
325
- get fxyz0() {
326
- return Array.from(this._fxyz0);
327
- }
328
-
329
- /**
330
- * Fractional coordinates of this atom image
331
- * @readonly
332
- * @type {float[]}
333
- */
334
- get fxyz() {
335
- return Array.from(this._fxyz);
336
- }
337
-
338
- /**
339
- * Index of the molecule this atom belongs to
340
- * @readonly
341
- * @type {int}
342
- */
343
- get moleculeIndex() {
344
- return this._model._molinds[this._index];
345
- }
346
-
347
- /**
348
- * Mesh corresponding to this atom image
349
- * @readonly
350
- * @type {AtomMesh}
351
- */
352
- get mesh() {
353
- var r = this.renderer;
354
- if (!this._mesh &amp;&amp; r) {
355
- this._mesh = new r.Primitives.AtomMesh(this._xyz, this.radius, this._color);
356
- this._mesh.image = this;
357
- }
358
- return this._mesh;
359
- }
360
-
361
- /**
362
- * Aura used to highlight this atom image
363
- * @readonly
364
- * @type {AuraMesh}
365
- */
366
- get aura() {
367
- var r = this.renderer;
368
- if (!this._aura &amp;&amp; r) {
369
- this._aura = new r.Primitives.AuraMesh({
370
- radius: this.radius,
371
- scale: 0.02
372
- });
373
- this.mesh.add(this._aura);
374
- }
375
-
376
- return this._aura;
377
- }
378
-
379
- // Get and set graphical properties
380
-
381
- /**
382
- * Whether the atom is visible
383
- * @type {bool}
384
- */
385
- get visible() {
386
- return this._visible;
387
- }
388
-
389
- set visible(v) {
390
-
391
- this._visible = v;
392
-
393
- var mesh = this.mesh;
394
-
395
- if (v) {
396
- this.renderer.add(mesh, 'model');
397
- } else {
398
- this.renderer.remove(mesh, 'model');
399
- }
400
-
401
- // Update aura visibility
402
- this.highlighted = this._highlighted;
403
-
404
- // Update connected bonds' visibility
405
- for (let i = 0; i &lt; this._bondsFrom.length; ++i) {
406
- let b = this._bondsFrom[i];
407
- b.visible = b._visible;
408
- }
409
-
410
- for (let i = 0; i &lt; this._bondsTo.length; ++i) {
411
- let b = this._bondsTo[i];
412
- b.visible = b._visible;
413
- }
414
- }
415
-
416
- /**
417
- * Starting radius of the atom
418
- * @type {float}
419
- */
420
- get baseRadius() {
421
- return this._base_radius;
422
- }
423
-
424
- set baseRadius(r) {
425
- if (r == null) { // Default value
426
- r = this.vdwRadius / 4.0;
427
- }
428
- this._base_radius = r;
429
- var mesh = this.mesh;
430
- mesh.atom_radius = this.radius;
431
- }
432
-
433
- /**
434
- * Scale of the atom
435
- * @type {float}
436
- */
437
- get scale() {
438
- return this._scale;
439
- }
440
-
441
- set scale(s) {
442
- if (s == null) {
443
- s = 1;
444
- }
445
- this._scale = s;
446
- var mesh = this.mesh;
447
- mesh.atom_radius = this.radius;
448
- }
449
-
450
- /**
451
- * Final radius of the atom (starting radius * scale)
452
- * @type {float}
453
- */
454
- get radius() {
455
- return this._scale * this._base_radius;
456
- }
457
-
458
- set radius(r) {
459
- if (r == null) {
460
- r == this.baseRadius;
461
- }
462
- this.scale = r / this._base_radius;
463
- }
464
-
465
- /**
466
- * Color of the atom
467
- * @type {int}
468
- */
469
- get color() {
470
- return this._color;
471
- }
472
-
473
- set color(c) {
474
- if (c === null) {
475
- c = this.cpkColor;
476
- this._uses_cpk = true;
477
- }
478
- else {
479
- this._uses_cpk = false;
480
- }
481
- this._color = c;
482
- var mesh = this.mesh;
483
- if (mesh) {
484
- mesh.atom_color = c;
485
- }
486
-
487
- _.map(this._bondsFrom, function(b) {
488
- b.color1 = c;
489
- });
490
-
491
- _.map(this._bondsTo, function(b) {
492
- b.color2 = c;
493
- });
494
-
495
- }
496
-
497
- /**
498
- * Opacity of the atom
499
- * @type {float}
500
- */
501
- get opacity() {
502
- return this._opacity;
503
- }
504
-
505
- set opacity(o) {
506
- if (o == null) {
507
- o = 1;
508
- }
509
- this._opacity = o;
510
- var mesh = this.mesh;
511
- mesh.atom_opacity = o;
512
-
513
- _.map(this._bondsFrom, function(b) {
514
- b.opacity1 = o;
515
- });
516
-
517
- _.map(this._bondsTo, function(b) {
518
- b.opacity2 = o;
519
- });
520
- }
521
-
522
- /**
523
- * Whether the atom is highlighted
524
- * @type {bool}
525
- */
526
- get highlighted() {
527
- return this._highlighted;
528
- }
529
-
530
- set highlighted(h) {
531
- if (h == null) {
532
- h = false;
533
- }
534
- this._highlighted = h;
535
- var aura = this.aura;
536
- if (h &amp;&amp; this._visible) {
537
- aura.visible = true;
538
- } else {
539
- aura.visible = false;
540
- }
541
- }
542
-
543
- /**
544
- * Add a text label to the atom.
545
- *
546
- * @param {String} text Content of the label
547
- * @param {String} name Name to use to refer to the label (necessary to overwrite/erase later)
548
- * @param {Object} parameters Dictionary of other options (e.g. font family, text color, etc. See TextSprite)
549
- */
550
- addLabel(text, name, parameters = {}) {
551
- this.removeLabel(name); // Precautionary
552
-
553
- var defaults = {
554
- faceCamera: true,
555
- fixScale: true,
556
- shift: [1.0*this.radius, 0, 0], // This just works well
557
- height: LABEL_HEIGHT,
558
- };
559
-
560
- parameters = _.merge(defaults, parameters);
561
- parameters.position = [0, 0, 0]; // This is not customizable
562
-
563
- var r = this.renderer;
564
- if (r) {
565
- var label = new r.Primitives.TextSprite(text, parameters);
566
- this._labels[name] = label;
567
- this.mesh.add(label);
568
- }
569
- }
570
-
571
- /**
572
- * Remove the label of a given name
573
- *
574
- * @param {String} name Name of the label
575
- */
576
- removeLabel(name) {
577
-
578
- let l = this._labels[name];
579
- if (l)
580
- this._mesh.remove(l);
581
- delete this._labels[name];
582
- }
583
-
584
- /**
585
- * Retrieve or set a label's properties
586
- *
587
- * @param {String} name Name of the label
588
- * @param {String} property Property to set
589
- * @param {?} value Value to set. If omitted, returns the current
590
- * value instead.
591
- */
592
- labelProperty(name, property, value = null) {
593
- if (value) {
594
- this._labels[name][property] = value;
595
- } else {
596
- return this._labels[name][property];
597
- }
598
- }
599
-
600
- /**
601
- * Add an ellipsoid to the atom.
602
- *
603
- * @param {TensorData | Object | Array} data The data to base the
604
- * ellipsoid on. Can be:
605
- * - a TensorData object;
606
- * - an Object with 'eigenvalues'
607
- * and 'eigenvectors' members
608
- * - an Array of the form
609
- * [eigenvalues, eigenvectors]
610
- * @param {String} name Name of the ellipsoid
611
- * @param {Object} parameters Additional options to
612
- * pass (see EllipsoidMesh)
613
- */
614
- addEllipsoid(data, name, parameters = {}) {
615
- this.removeEllipsoid(name);
616
-
617
- parameters = _.clone(parameters); // Avoid editing the reference object
618
-
619
- if (data instanceof Array) {
620
- parameters.eigenvalues = data[0];
621
- parameters.eigenvectors = data[1];
622
- } else {
623
- parameters.eigenvalues = data.eigenvalues;
624
- parameters.eigenvectors = data.eigenvectors;
625
- }
626
-
627
- if (parameters.ditherSeed == null) {
628
- // As long as it's consistent for a given atom, the actual value is irrelevant
629
- let seed = utils.hashCode(this._fxyz + name);
630
- parameters.ditherSeed = seed/4294967295.0; // Reduce to ]0.5,-0.5]
631
- }
632
-
633
- var r = this.renderer;
634
- if (r) {
635
- var ellips = new r.Primitives.EllipsoidMesh(parameters);
636
- this._ellipsoids[name] = ellips;
637
- this.mesh.add(ellips);
638
- }
639
- }
640
-
641
- /**
642
- * Remove the ellipsoid with a given name
643
- *
644
- * @param {String} name Name of the ellipsoid
645
- */
646
- removeEllipsoid(name) {
647
- let l = this._ellipsoids[name];
648
- if (l)
649
- this._mesh.remove(l);
650
- delete this._ellipsoids[name];
651
- }
652
-
653
- /**
654
- * Retrieve or set an ellipsoid's properties
655
- *
656
- * @param {String} name Name of the ellipsoid
657
- * @param {String} property Property to set
658
- * @param {?} value Value to set. If omitted, returns the current
659
- * value instead.
660
- */
661
- ellipsoidProperty(name, property, value = null) {
662
- if (value) {
663
- this._ellipsoids[name][property] = value;
664
- } else {
665
- return this._ellipsoids[name][property];
666
- }
667
- }
668
-
669
- /**
670
- * Get the value for one array for this image
671
- * @param {String} name Name of the array
672
- *
673
- * @return {*} Value of the array for this atom
674
- */
675
- getArrayValue(name) {
676
- return this._model.getArray(name)[this._index];
677
- }
678
-
679
- // Check equality with another image
680
- equals(ai) {
681
- return (this._model == ai._model &amp;&amp;
682
- this._index == ai._index &amp;&amp;
683
- _.isEqual(this._ijk, ai._ijk));
684
- }
685
-
686
- // Return a copy, possibly shifted to a different cell
687
- copy(shift = [0, 0, 0]) {
688
- return new AtomImage(this._model,
689
- this._index,
690
- mjs.add(this._ijk, shift));
691
- }
692
- }
693
-
694
- /** An 'image' of a single bond in the model. This represents the connection
695
- between two specific AtomImages */
696
- class BondImage {
697
-
698
-
699
- /**
700
- * @class
701
- * @param {Model} model The model from which the image is from
702
- * @param {AtomImage} im1 AtomImage from which the bond starts
703
- * @param {AtomImage} im2 AtomImage to which the bond ends
704
- */
705
- constructor(model, im1, im2) {
706
-
707
- this._model = model;
708
- this._im1 = im1;
709
- this._im2 = im2;
710
-
711
- this._im1._bondsFrom.push(this);
712
- this._im2._bondsTo.push(this);
713
-
714
- this._length = mjs.distance(this._im1.xyz, this._im2.xyz);
715
-
716
- this._key = this._im1.imgIndex + '_' + this._im2.imgIndex;
717
-
718
- // Visual properties
719
- this._visible = true;
720
- this._radius = 0.2;
721
- this._opacity = 1.0;
722
-
723
- this._mesh = null; // Created on first request
724
-
725
- }
726
-
727
- /**
728
- * Model this bond belongs to
729
- * @readonly
730
- * @type {Model}
731
- */
732
- get model() {
733
- return this._model;
734
- }
735
-
736
- /**
737
- * Renderer used by this bond
738
- * @readonly
739
- * @type {Renderer}
740
- */
741
- get renderer() {
742
- var m = this.model;
743
- if (m) {
744
- return m._renderer;
745
- }
746
- return null;
747
- }
748
-
749
- /**
750
- * First atom connected to this bond
751
- * @readonly
752
- * @type {AtomImage}
753
- */
754
- get atom1() {
755
- return this._im1;
756
- }
757
-
758
- /**
759
- * Second atom connected to this bond
760
- * @readonly
761
- * @type {AtomImage}
762
- */
763
- get atom2() {
764
- return this._im2;
765
- }
766
-
767
- /**
768
- * A unique string key used to quickly reference the bond
769
- * @readonly
770
- * @type {String}
771
- */
772
- get key() {
773
- // Used in dictionary for quick reference
774
- return this._key;
775
- }
776
-
777
- /**
778
- * Bond length in Angstroms
779
- * @readonly
780
- * @type {float}
781
- */
782
- get length() {
783
- return this._length;
784
- }
785
-
786
- /**
787
- * Mesh corresponding to this bond image
788
- * @readonly
789
- * @type {AtomMesh}
790
- */
791
- get mesh() {
792
- var r = this.renderer;
793
- if (!this._mesh &amp;&amp; r) {
794
- this._mesh = new r.Primitives.BondMesh(this.atom1.xyz, this.atom2.xyz,
795
- this._radius,
796
- this.atom1.color, this.atom2.color);
797
- }
798
- return this._mesh;
799
- }
800
-
801
- /**
802
- * Radius of the bond
803
- * @type {float}
804
- */
805
- get radius() {
806
- return this._radius;
807
- }
808
-
809
- set radius(r) {
810
- if (r == null) {
811
- r = 0.2;
812
- }
813
- this._radius = r;
814
- var mesh = this.mesh;
815
- if (mesh) {
816
- mesh.bond_radius = r;
817
- }
818
- }
819
-
820
- /**
821
- * First color of the bond
822
- * @type {int}
823
- */
824
- set color1(c) {
825
- if (c == null) {
826
- c = this._im1.color;
827
- }
828
- var mesh = this.mesh;
829
- if (mesh) {
830
- mesh.bond_color_1 = c;
831
- }
832
- }
833
-
834
- /**
835
- * Second color of the bond
836
- * @type {int}
837
- */
838
- set color2(c) {
839
- if (c == null) {
840
- c = this._im2.color;
841
- }
842
- var mesh = this.mesh;
843
- if (mesh) {
844
- mesh.bond_color_2 = c;
845
- }
846
- }
847
-
848
- /**
849
- * First opacity of the bond
850
- * @type {float}
851
- */
852
- set opacity1(o) {
853
- if (o == null) {
854
- o = this._im1.opacity;
855
- }
856
- var mesh = this.mesh;
857
- if (mesh) {
858
- mesh.bond_opacity_1 = o;
859
- }
860
- }
861
-
862
- /**
863
- * Second opacity of the bond
864
- * @type {float}
865
- */
866
- set opacity2(o) {
867
- if (o == null) {
868
- o = this._im2.opacity;
869
- }
870
- var mesh = this.mesh;
871
- if (mesh) {
872
- mesh.bond_opacity_2 = o;
873
- }
874
- }
875
-
876
- /**
877
- * Whether the bond is visible
878
- * @type {bool}
879
- */
880
- get visible() {
881
- return this._visible;
882
- }
883
-
884
- set visible(v) {
885
-
886
- this._visible = v;
887
- v = v &amp;&amp; this.atom1.visible &amp;&amp; this.atom2.visible;
888
-
889
- var mesh = this.mesh;
890
- if (v) {
891
- this.renderer.add(mesh, 'model');
892
- } else {
893
- this.renderer.remove(mesh, 'model');
894
- }
895
-
896
- }
897
- }
898
-
899
- class Model {
900
-
901
-
902
- /**
903
- * An object containing an Atomic structure and taking care of its periodic
904
- * nature, allowing querying and selection, and so on.
905
- * @class
906
- * @param {crystcif.Atoms} atoms Atomic structure, in crystcif's Atoms format
907
- * @param {Object} parameters Additional options:
908
- *
909
- * - `supercell`
910
- * - `molecularCrystal` (if true, load full molecules in central unit cell)
911
- * - `useNMRActiveIsotopes` (if true, all isotopes are set by default to the most common
912
- * one with non-zero spin)
913
- * - `vdwScaling` (scale van der Waals radii by a constant factor)
914
- * - `vdwElementScaling` (table of per-element factors to scale VdW radii by)
915
- */
916
- constructor(atoms, parameters = {}) {
917
-
918
- var defaults = {
919
- supercell: [1, 1, 1],
920
- molecularCrystal: false,
921
- useNMRActiveIsotopes: false,
922
- vdwScaling: 1.0,
923
- vdwElementScaling: {}
924
- };
925
-
926
- parameters = _.merge(defaults, parameters);
927
-
928
- this._vdwScaling = parameters.vdwScaling;
929
- this._vdwElementScaling = parameters.vdwElementScaling;
930
-
931
- const initMolecules = ((atoms, supercell) => {
932
-
933
- if (!(atoms instanceof Atoms)) {
934
- throw new Error('Model must be initialised with a loaded Atoms object');
935
- }
936
-
937
- this._atoms_base = atoms;
938
- this._data = {};
939
-
940
- /* Load the positions, cell, and other key data
941
- Important: to save memory, we're simply storing references.
942
- These are NOT to be changed!
943
- */
944
-
945
-
946
- this._elems = this._atoms_base._arrays['symbols'];
947
- this._isotopes = this._elems.map((el) => {
948
- const iso = parameters.useNMRActiveIsotopes? 'nmr' : null;
949
- let isodata = data.getIsotopeData(el, iso);
950
- if (isodata === null) {
951
- // No NMR active isotope?
952
- isodata = data.getIsotopeData(el);
953
- }
954
-
955
- return isodata;
956
- });
957
- this._nums = this._atoms_base._arrays['numbers'];
958
- this._positions = this._atoms_base._arrays['positions'];
959
- this._cell = this._atoms_base._cell;
960
- this._pbc = this._atoms_base._pbc;
961
- this._periodic = !this._pbc.includes(false);
962
- this._inv_cell = this._atoms_base._inv_cell;
963
- this._supercell = [1, 1, 1];
964
- this._supercell_grid = [
965
- [0, 0, 0]
966
- ];
967
-
968
- // Species indices (used for labels)
969
- let sp_count = {};
970
- this._species_indices = [];
971
- this._species_indices = this._elems.map((s, i) => {
972
- let c = sp_count[s];
973
- c = c? c : 0;
974
- sp_count[s] = c+1;
975
- return c;
976
- });
977
-
978
- let has_cif_labels = false;
979
-
980
- // Crystallographic labels
981
- if ('labels' in this._atoms_base._arrays) {
982
- // If any of the labels don't match the element,
983
- // then we're assuming they're crystallographic (CIF-style) labels
984
- if (this._atoms_base._arrays['labels'].some((l, i) => {
985
- return l !== this._elems[i];
986
- })) {
987
- // then use them
988
- has_cif_labels = true;
989
- this._labels = this._atoms_base._arrays['labels'];
990
- } else {
991
- // otherwise, build new ones and
992
- // throw a warning to user syaing we're doing this
993
- this._labels = [];
994
- for (let i = 0; i &lt; this._elems.length; ++i) {
995
- this._labels.push(this._elems[i] + '_' + (this._species_indices[i]+1));
996
- }
997
- console.warn('No crystallographic labels found in CIF file. Building new ones.');
998
- }
999
- }
1000
- else {
1001
- // Build them
1002
- this._labels = [];
1003
- for (let i = 0; i &lt; this._elems.length; ++i) {
1004
- this._labels.push(this._elems[i] + '_' + (this._species_indices[i]+1));
1005
- }
1006
- }
1007
-
1008
- this._has_cif_labels = has_cif_labels; // defaults to false
1009
-
1010
- // Cryst label indices
1011
- let lab_count = {};
1012
- this._label_indices = [];
1013
- this._label_indices = this._labels.map((s, i) => {
1014
- let c = lab_count[s];
1015
- c = c? c : 0;
1016
- lab_count[s] = c+1;
1017
- return c;
1018
- });
1019
-
1020
- if (this._periodic) {
1021
- // R matrix: indispensable for calculations of periodic distances
1022
- this._r_matrix = mjs.multiply(this._cell, mjs.transpose(this._cell));
1023
- var ediag = mjs.eigs(this._r_matrix);
1024
- // Sort by eigenvalue
1025
- var evecs = ediag.eigenvectors.map(e => e.vector);
1026
- ediag = _.zip(ediag.values, evecs);
1027
- ediag = _.sortBy(ediag, function(x) {
1028
- return x[0];
1029
- });
1030
- ediag = _.unzip(ediag);
1031
-
1032
- this._r_diag = {
1033
- values: ediag[0],
1034
- vectors: ediag[1],
1035
- };
1036
-
1037
- this._supercell = supercell; // Default
1038
- this._supercell_grid = utils.supercellGrid(supercell);
1039
- this._scaled_positions = this._atoms_base.get_scaled_positions();
1040
- }
1041
-
1042
- // Compile all images for this supercell
1043
- this._atom_images = this._atomImages();
1044
-
1045
- this._computeBonds();
1046
- this._computeMolecules();
1047
-
1048
-
1049
- }).bind(this);
1050
-
1051
- initMolecules(atoms, parameters.supercell);
1052
-
1053
- // if parameters.molecularCrystal, is null, we need to check if the atoms
1054
- // contains organic molecules -- i.e. if there is at least one C-H bond
1055
- if (parameters.molecularCrystal || (parameters.molecularCrystal === null &amp;&amp;
1056
- this._queryCHBond())) {
1057
- this._molecularCrystal = true;
1058
- atoms = _.cloneDeep(atoms);
1059
- var pos = this.positions;
1060
- for (let i = 0; i &lt; this.length; ++i) {
1061
- let mol_i = this._molinds[i];
1062
- let mol = this._molecules[mol_i];
1063
- for (let j = 0; j &lt; mol.length; ++j) {
1064
- var a = mol[j];
1065
- if (a.index == i) {
1066
- pos[i] = mjs.add(pos[i], this.fracToAbs(a.cell));
1067
- }
1068
- }
1069
- }
1070
-
1071
- atoms.set_array('positions', pos);
1072
- initMolecules(atoms, parameters.supercell);
1073
- }
1074
-
1075
- this._primitives = {}; // Any additional primitives drawn on this model
1076
-
1077
- this._bond_images = this._bondImages();
1078
-
1079
- // A special ModelView for convenience
1080
- this._all = new ModelView(this, _.range(this._atom_images.length));
1081
-
1082
- // Parser for queries
1083
- this._qparse = new QueryParser({
1084
- 'all': this._queryAll,
1085
- 'indices': this._queryIndices,
1086
- 'elements': this._queryElements,
1087
- 'cell': this._queryCell,
1088
- 'box': this._queryBox,
1089
- 'sphere': this._querySphere,
1090
- 'bonded': this._queryBonded,
1091
- 'molecule': this._queryMolecule,
1092
- }, this);
1093
-
1094
- // By default no rendering
1095
- this.renderer = null;
1096
- }
1097
-
1098
- // Using the .get_ methods of _atoms guarantees these are copies,
1099
- // not pointers to the real thing
1100
-
1101
- /**
1102
- * Number of atoms in this model's original cell
1103
- * @readonly
1104
- * @type {int}
1105
- */
1106
- get length() {
1107
- return this._atoms_base.length();
1108
- }
1109
-
1110
- /**
1111
- * Chemical symbols in this model's original cell
1112
- * @readonly
1113
- * @type {String[]}
1114
- */
1115
- get symbols() {
1116
- return this._atoms_base.get_chemical_symbols();
1117
- }
1118
-
1119
- /**
1120
- * Atomic numbers in this model's original cell
1121
- * @readonly
1122
- * @type {int[]}
1123
- */
1124
- get numbers() {
1125
- return this._atoms_base.get_atomic_numbers();
1126
- }
1127
-
1128
- /**
1129
- * Coordinates of the atoms in this model's original cell
1130
- * @readonly
1131
- * @type {Array[]}
1132
- */
1133
- get positions() {
1134
- return this._atoms_base.get_positions();
1135
- }
1136
-
1137
- /**
1138
- * Fractional coordinates of the atoms in this model's original cell
1139
- * @readonly
1140
- * @type {Array[]}
1141
- */
1142
- get scaledPositions() {
1143
- return this._atoms_base.get_scaled_positions();
1144
- }
1145
-
1146
- /**
1147
- * Unit cell of the model's original cell
1148
- * @readonly
1149
- * @type {Array[]}
1150
- */
1151
- get cell() {
1152
- return this._atoms_base.get_cell();
1153
- }
1154
-
1155
- /**
1156
- * Periodic boundary conditions
1157
- * @readonly
1158
- * @type {bool[]}
1159
- */
1160
- get pbc() {
1161
- return this._atoms_base.get_pbc();
1162
- }
1163
-
1164
- /**
1165
- * Additional information from the model's original cell
1166
- * @readonly
1167
- * @type {Object}
1168
- */
1169
- get info() {
1170
- return this._atoms_base.info;
1171
- }
1172
-
1173
- /**
1174
- * Whether this model is periodic in all three directions of space
1175
- * @readonly
1176
- * @type {bool}
1177
- */
1178
- get periodic() {
1179
- return this._periodic;
1180
- }
1181
-
1182
- /**
1183
- * Indices of each atom by their species (e.g. C1, C2, H1, C3, H2, etc.)
1184
- * @readonly
1185
- * @type {int[]}
1186
- */
1187
- get speciesIndices() {
1188
- return Array.from(this._species_indices);
1189
- }
1190
-
1191
- /**
1192
- * Crystallographic labels of each atom
1193
- * @readonly
1194
- * @type {String[]}
1195
- */
1196
- get crystalLabels() {
1197
- return Array.from(this._labels);
1198
- }
1199
-
1200
- /**
1201
- * Shape of the supercell for this model
1202
- * @readonly
1203
- * @type {int[]}
1204
- */
1205
- get supercell() {
1206
- return Array.from(this._supercell);
1207
- }
1208
-
1209
- /**
1210
- * Full grid of origin coordinates of the cells making up the supercell
1211
- * @readonly
1212
- * @type {Array[]}
1213
- */
1214
- get supercellGrid() {
1215
- return JSON.parse(JSON.stringify(this._supercell_grid));
1216
- }
1217
-
1218
- /**
1219
- * Atom images in this model
1220
- * @readonly
1221
- * @type {AtomImage[]}
1222
- */
1223
- get atoms() {
1224
- return Array.from(this._atom_images);
1225
- }
1226
-
1227
- /**
1228
- * ModelView containing all the atoms of the image
1229
- * @readonly
1230
- * @type {ModelView}
1231
- */
1232
- get all() {
1233
- return this._all;
1234
- }
1235
-
1236
- /**
1237
- * Graphical object representing the unit cell's axes
1238
- * @readonly
1239
- * @type {AxesMesh}
1240
- */
1241
- get axes() {
1242
- return this._cartesian_axes;
1243
- }
1244
-
1245
- /**
1246
- * Graphical object representing the unit cell's box
1247
- * @readonly
1248
- * @type {BoxMesh}
1249
- */
1250
- get box() {
1251
- return this._cartesian_box;
1252
- }
1253
-
1254
- /**
1255
- * Global scaling factor for Van der Waals radii
1256
- * @readonly
1257
- * @type {float}
1258
- */
1259
- get vdwScaling() {
1260
- return this._vdwScaling;
1261
- }
1262
-
1263
- /**
1264
- * Table of scaling factors by element for Van der Waals radii
1265
- * @readonly
1266
- * @type {Object}
1267
- */
1268
- get vdwElementScaling() {
1269
- return JSON.parse(JSON.stringify(this._vdwElementScaling));
1270
- }
1271
-
1272
- /**
1273
- * Renderer used for this model's graphics
1274
- * @type {Renderer}
1275
- */
1276
- set renderer(r) {
1277
-
1278
-
1279
- if (r) {
1280
- this._renderer = r;
1281
- if (this.periodic) {
1282
- // Create axes and box
1283
- if (!this._cartesian_box) {
1284
- this._cartesian_box = new r.Primitives.BoxMesh(this.cell, {color:r.theme.cell_line_color});
1285
- }
1286
- if (!this._cartesian_axes) {
1287
- this._cartesian_axes = new r.Primitives.AxesMesh(this.cell, {
1288
- linewidth: 1.5
1289
- });
1290
- }
1291
- r.add(this._cartesian_box);
1292
- r.add(this._cartesian_axes);
1293
- }
1294
-
1295
- // And the primitives
1296
- for (var name in this._primitives) {
1297
- var p = this._primitives[name];
1298
- r.add(p);
1299
- }
1300
-
1301
- } else {
1302
-
1303
- if (this._renderer)
1304
- this._renderer.clear();
1305
-
1306
- this._renderer = null;
1307
-
1308
- }
1309
- }
1310
-
1311
- // Set and get arrays on the underlying Atoms object
1312
- /**
1313
- * Set an array for the underlying Atoms object
1314
- * @param {String} name Name of the array to use
1315
- * @param {Array} arr Array to store
1316
- */
1317
- setArray(name, arr) {
1318
- this._atoms_base.set_array(name, arr);
1319
- }
1320
-
1321
- /**
1322
- * Retrieve an array from the underlying Atoms object
1323
- * @param {String} name Name of the array to retrieve
1324
- * @return {Array} Retrieved array
1325
- */
1326
- getArray(name) {
1327
- return this._atoms_base.get_array(name);
1328
- }
1329
-
1330
- /**
1331
- * Check if an array exists in the underlying Atoms object
1332
- * @param {String} name Name of the array to check
1333
- * @return {bool} Whether the array exists
1334
- */
1335
- hasArray(name) {
1336
- return (name in this._atoms_base._arrays);
1337
- }
1338
-
1339
- /**
1340
- * Delete an array from the underlying Atoms object
1341
- * @param {String} name Name of the array to delete
1342
- */
1343
- deleteArray(name) {
1344
- delete this._atoms_base._arrays[name];
1345
- }
1346
-
1347
- // These functions are for adding and removing graphical representations
1348
- // that are meant to be drawn on to of the existing 3D model
1349
-
1350
- /**
1351
- * Add link drawn on model
1352
- *
1353
- * @param {Atom | Array} from Starting point
1354
- * @param {Atom | Array} to End point
1355
- * @param {String} name Name to use for the link object
1356
- * @param {String} label Text label to add to the link
1357
- * @param {Object} parameters Additional parameters (see LineMesh)
1358
- */
1359
- addLink(from, to, name = 'link', label = null, parameters = {}) {
1360
-
1361
- this.removeGraphics(name);
1362
-
1363
- parameters = _.clone(parameters); // Avoid editing the reference object
1364
-
1365
- var r = this._renderer;
1366
- if (r) {
1367
- var link = new r.Primitives.LineMesh(from, to, parameters);
1368
-
1369
- this._primitives[name] = link;
1370
- r.add(link);
1371
-
1372
- if (label) {
1373
- var text = new r.Primitives.TextSprite(label, {
1374
- color: parameters.color,
1375
- fixScale: true,
1376
- faceCamera: true,
1377
- height: parameters.height || LABEL_HEIGHT,
1378
- shift: [LABEL_HEIGHT, 0, 0],
1379
- onOverlay: parameters.onOverlay
1380
- });
1381
- link.add(text);
1382
- }
1383
- }
1384
- }
1385
-
1386
- /**
1387
- * Add a sphere drawn on model
1388
- *
1389
- * @param {Atom | Array} center Center of the sphere
1390
- * @param {float} radius Radius of the sphere
1391
- * @param {String} name Name to use for the sphere object
1392
- * @param {Object} parameters Additional parameters (see EllipsoidMesh)
1393
- */
1394
- addSphere(center, radius, name='sphere', parameters = {}) {
1395
-
1396
- this.removeGraphics(name);
1397
-
1398
- var r = this._renderer;
1399
- if (r) {
1400
-
1401
- parameters = _.merge({
1402
- color: 0xffffff,
1403
- opacity: 0.5,
1404
- opacityMode: r.Primitives.EllipsoidMesh.DITHER,
1405
- showCircles: true,
1406
- showAxes: true
1407
- }, parameters); // Avoid editing the reference object
1408
-
1409
- var sph = new r.Primitives.EllipsoidMesh({
1410
- color: parameters.color,
1411
- opacity: parameters.opacity,
1412
- opacityMode: parameters.opacityMode,
1413
- showCircles: parameters.showCircles,
1414
- showAxes: parameters.showAxes,
1415
- scalingFactor: radius,
1416
- center: center
1417
- });
1418
-
1419
- this._primitives[name] = sph;
1420
- r.add(sph);
1421
- }
1422
- }
1423
-
1424
- /**
1425
- * Remove the graphical object with a given name
1426
- *
1427
- * @param {String} name Name of the graphical object to remove
1428
- */
1429
- removeGraphics(name) {
1430
- var g = this._primitives[name];
1431
- var r = this._renderer;
1432
- if (g &amp;&amp; r)
1433
- r.remove(g);
1434
- delete this._primitives[name];
1435
- }
1436
-
1437
- /**
1438
- * Remove all graphical objects
1439
- */
1440
- clearGraphics() {
1441
- var r = this._renderer;
1442
-
1443
- if (r) {
1444
- _.map(this._primitives, function(g) {
1445
- r.remove(g);
1446
- });
1447
- }
1448
-
1449
- this._primitives = {};
1450
- }
1451
-
1452
- /**
1453
- * Compute the bonds within the model. For internal use
1454
- * @private
1455
- */
1456
- _computeBonds() {
1457
-
1458
- var N = this.length;
1459
- this._bondmat = Array(N); // Bond matrix
1460
- this._bondmat = _.map(this._bondmat, function() {
1461
- return _.map(Array(N), function() {
1462
- return [];
1463
- });
1464
- });
1465
-
1466
- // Van der Waals radii by element
1467
- var vdwf = this._vdwScaling;
1468
- var vdwf_table = this._vdwElementScaling;
1469
-
1470
- var vdwr = _.map(this.symbols, function(s) {
1471
- var f = vdwf;
1472
-
1473
- if (s in vdwf_table) {
1474
- f = vdwf_table[s];
1475
- }
1476
-
1477
- return data.getVdwRadius(s)*f;
1478
- });
1479
-
1480
- var maxr = _.max(vdwr);
1481
-
1482
- var cell = this.cell;
1483
- var sgrid = [
1484
- [0, 0, 0]
1485
- ];
1486
- var p = this._positions;
1487
-
1488
- if (this._periodic) {
1489
- var scell = this.minimumSupercell(maxr);
1490
- sgrid = utils.supercellGrid(scell);
1491
- }
1492
-
1493
- // Now iterate over all atom pairs
1494
- for (let i = 0; i &lt; this.length; ++i) {
1495
-
1496
- var p1 = p[i];
1497
-
1498
- for (let j = i; j &lt; this.length; ++j) {
1499
-
1500
- var p2 = p[j];
1501
-
1502
- for (let k = 0; k &lt; sgrid.length; ++k) {
1503
- var c = sgrid[k];
1504
- if ((i == j) &amp;&amp; (c[0] == 0 &amp;&amp; c[1] == 0 &amp;&amp; c[2] == 0)) {
1505
- // Just the same atom, skip
1506
- continue;
1507
- }
1508
- var r = [0, 0, 0];
1509
- // Here we write the algebra explicitly
1510
- // for efficiency reasons
1511
- if (this._periodic) {
1512
- r[0] = c[0] * cell[0][0] + c[1] * cell[1][0] + c[2] * cell[2][0];
1513
- r[1] = c[0] * cell[0][1] + c[1] * cell[1][1] + c[2] * cell[2][1];
1514
- r[2] = c[0] * cell[0][2] + c[1] * cell[1][2] + c[2] * cell[2][2];
1515
- }
1516
- r = [p2[0] - p1[0] + r[0], p2[1] - p1[1] + r[1], p2[2] - p1[2] + r[2]];
1517
- r = Math.sqrt(r[0] * r[0] + r[1] * r[1] + r[2] * r[2]);
1518
- if (r &lt; (vdwr[i] + vdwr[j]) / 2.0) {
1519
- // Bond!
1520
- this._bondmat[i][j].push([c[0], c[1], c[2]]);
1521
- this._bondmat[j][i].push([-c[0], -c[1], -c[2]]);
1522
- }
1523
- }
1524
- }
1525
- }
1526
- }
1527
-
1528
- /**
1529
- * Check if any C-H bonds are present
1530
- * @return {bool} Whether any C-H bonds are present
1531
- * @private
1532
- */
1533
- _queryCHBond() {
1534
- // make sure bondmat is present
1535
- if (!this._bondmat) {
1536
- this._computeBonds();
1537
- }
1538
-
1539
- var symbols = this._atoms_base.get_chemical_symbols();
1540
- var bondmat = this._bondmat;
1541
- var n = symbols.length;
1542
- for (var i = 0; i &lt; n; i++) {
1543
- var bonds = bondmat[i];
1544
- var a = symbols[i];
1545
- if (a == 'C') {
1546
- // loop over bonds and check if any are H
1547
- for (var j = 0; j &lt; n; j++) {
1548
- // if bonds[j] is not an empty array
1549
- if (bonds[j].length) {
1550
- if (symbols[j] == 'H') {
1551
- return true;
1552
- }
1553
- }
1554
- }
1555
- }
1556
- }
1557
- return false;
1558
- }
1559
-
1560
-
1561
-
1562
- /**
1563
- * Compute the molecules within the model. For internal use
1564
- * @private
1565
- */
1566
- _computeMolecules() {
1567
-
1568
- this._molecules = [];
1569
- this._molinds = [];
1570
-
1571
- if (this.length &lt; 2) {
1572
- // No molecules can be computed
1573
- this._molecules = null;
1574
- return;
1575
- }
1576
-
1577
- var mol_sets = [];
1578
- var unsorted_atoms = _.range(this.length);
1579
-
1580
- while (unsorted_atoms.length > 0) {
1581
- var mol_queue = [
1582
- [unsorted_atoms.shift(), [0, 0, 0]]
1583
- ];
1584
- var current_mol = [];
1585
- var current_mol_cells = [];
1586
- while (mol_queue.length > 0) {
1587
- var ac1 = mol_queue.shift();
1588
- var a1 = ac1[0];
1589
- var c1 = ac1[1];
1590
-
1591
- current_mol.push(a1);
1592
- current_mol_cells.push(c1);
1593
- // Find linked atoms
1594
- var link1 = this._bondmat[a1];
1595
- for (let i in link1) {
1596
- var a2 = parseInt(i);
1597
- var link12 = link1[i];
1598
- // Is a2 still unsorted?
1599
- if (!unsorted_atoms.includes(a2) || link12.length == 0)
1600
- continue;
1601
-
1602
- for (let j = 0; j &lt; link12.length; ++j) {
1603
- var c2 = link12[j];
1604
- mol_queue.push([a2, mjs.add(c1, c2)]);
1605
- }
1606
-
1607
- unsorted_atoms.splice(unsorted_atoms.indexOf(a2), 1);
1608
- }
1609
- }
1610
- mol_sets.push([
1611
- current_mol,
1612
- current_mol_cells
1613
- ]);
1614
- }
1615
-
1616
- for (let i = 0; i &lt; mol_sets.length; ++i) {
1617
-
1618
- var mol = [];
1619
- for (let j = 0; j &lt; mol_sets[i][0].length; ++j) {
1620
- mol.push({
1621
- 'index': mol_sets[i][0][j],
1622
- 'cell': mol_sets[i][1][j]
1623
- });
1624
- }
1625
-
1626
- this._molecules.push(mol);
1627
- }
1628
-
1629
- // Assign the molecule's index for each atom
1630
- this._molinds = _.range(this.length);
1631
-
1632
- for (let i = 0; i &lt; this._molecules.length; ++i) {
1633
- var m = this._molecules[i];
1634
- for (let j = 0; j &lt; m.length; ++j) {
1635
- var a = m[j];
1636
- this._molinds[a.index] = i;
1637
- }
1638
- }
1639
- }
1640
-
1641
- /**
1642
- * Return a list of all AtomImages within the given supercell.
1643
- *
1644
- * @private
1645
- * @return {AtomImage[]} List of AtomImage objects
1646
- */
1647
- _atomImages() {
1648
- var sgrid = this._supercell_grid;
1649
- var imgs = [];
1650
- var indices = _.range(this.length);
1651
- var model = this;
1652
- for (let i = 0; i &lt; sgrid.length; ++i) {
1653
- var cell = sgrid[i];
1654
- imgs = imgs.concat(_.map(indices, function(a) {
1655
- return new AtomImage(model, a, cell);
1656
- }));
1657
- }
1658
- return imgs;
1659
- }
1660
-
1661
- /**
1662
- * Return a list of all BondImages within the given supercell.
1663
- *
1664
- * @private
1665
- * @return {BondImage[]} List of BondImage objects
1666
- */
1667
- _bondImages() {
1668
- var bondimgs = [];
1669
-
1670
- for (let ii = 0; ii &lt; this._atom_images.length; ++ii) {
1671
- var im1 = this._atom_images[ii];
1672
- var i = im1.index;
1673
- var bonds = this._bondmat[i];
1674
- var c1 = im1.ijk;
1675
- for (let j = i; j &lt; this.length; ++j) {
1676
- var blist = bonds[j];
1677
- for (let k = 0; k &lt; blist.length; ++k) {
1678
- var r = blist[k];
1679
- var c2 = [c1[0] + r[0], c1[1] + r[1], c1[2] + r[2]];
1680
- var jj = utils.supercellIndex(j, c2, this._supercell, this.length);
1681
- if (jj >= 0 &amp;&amp; jj &lt; this._atom_images.length) {
1682
- var im2 = this._atom_images[jj];
1683
- var bimg = new BondImage(this, im1, im2);
1684
- bondimgs.push(bimg);
1685
- }
1686
- }
1687
- }
1688
- }
1689
-
1690
- return bondimgs;
1691
- }
1692
-
1693
- /**
1694
- * Convert fractional coordinates to absolute
1695
- *
1696
- * @param {float[]} fx Fractional coordinates
1697
- * @return {float[]} Absolute coordinates
1698
- */
1699
- fracToAbs(fx) {
1700
- if (!this.periodic) {
1701
- return null
1702
- }
1703
- var c = this._atoms_base._cell;
1704
- return [fx[0] * c[0][0] + fx[1] * c[1][0] + fx[2] * c[2][0],
1705
- fx[0] * c[0][1] + fx[1] * c[1][1] + fx[2] * c[2][1],
1706
- fx[0] * c[0][2] + fx[1] * c[1][2] + fx[2] * c[2][2]
1707
- ];
1708
- }
1709
-
1710
- /**
1711
- * Convert absolute coordinates to fractional
1712
- *
1713
- * @param {float[]} x Absolute coordinates
1714
- * @return {float[]} Fractional coordinates
1715
- */
1716
- absToFrac(x) {
1717
- if (!this.periodic) {
1718
- return null
1719
- }
1720
- var ic = this._atoms_base._inv_cell;
1721
- return [x[0] * ic[0][0] + x[1] * ic[1][0] + x[2] * ic[2][0],
1722
- x[0] * ic[0][1] + x[1] * ic[1][1] + x[2] * ic[2][1],
1723
- x[0] * ic[0][2] + x[1] * ic[1][2] + x[2] * ic[2][2]
1724
- ];
1725
- }
1726
-
1727
- /**
1728
- * Compute and return the minimum supercell that guarantees
1729
- * containing all atoms at a maximum distance r from those in the
1730
- * [0,0,0] cell.
1731
- *
1732
- * @param {float} r Maximum distance that must be contained within the supercell
1733
- */
1734
- minimumSupercell(r) {
1735
-
1736
- var diag = _.map(this._r_diag.values, function(x) {
1737
- return mjs.pow(x, -0.5)
1738
- });
1739
- var utransf_mat = mjs.multiply(this._r_diag.vectors, mjs.diag(diag));
1740
- var utransf_norm = mjs.transpose(utransf_mat);
1741
- for (let i = 0; i &lt; 3; ++i) {
1742
- var norm = mjs.norm(utransf_mat[i]);
1743
- for (let j = 0; j &lt; 3; ++j) {
1744
- utransf_norm[j][i] *= r / norm;
1745
- }
1746
- }
1747
- var qmatrix = mjs.multiply(utransf_mat, utransf_norm);
1748
- var scell = [];
1749
- for (let i = 0; i &lt; 3; ++i) {
1750
- var b = 0;
1751
- for (let j = 0; j &lt; 3; ++j) {
1752
- b = Math.max(Math.ceil(Math.abs(qmatrix[i][j])), b);
1753
- }
1754
- scell.push(2 * b + 1);
1755
- }
1756
-
1757
- return scell;
1758
- }
1759
-
1760
- /**
1761
- * Find a group of atoms based on a given query and return as AtomImages
1762
- * @param {Array} query A search query for atoms. Must use nested lists
1763
- * of types and arguments, and can use logic
1764
- * operators $and, $or and $xor.
1765
- * @return {ModelView} ModelView object for found atoms
1766
- */
1767
- find(query) {
1768
- var found = this._qparse.parse(query);
1769
- return this.view(found);
1770
- }
1771
-
1772
- /** Create a new ModelView for this model, using a given list of indices
1773
- * @param {Array} indices Indices of atoms to include in the ModelView
1774
- *
1775
- * @return {ModelView} ModelView object for specified indices
1776
- */
1777
- view(indices) {
1778
- return new ModelView(this, indices);
1779
- }
1780
-
1781
- /**
1782
- * Reconstruct a {@link ModelView} from a plain array of atom-image indices,
1783
- * as produced by {@link ModelView#toIndices}. This is the stable public API
1784
- * for deserialising a saved selection.
1785
- *
1786
- * @param {number[]} indices
1787
- * @return {ModelView}
1788
- */
1789
- viewFromIndices(indices = []) {
1790
- return this.view(indices);
1791
- }
1792
-
1793
- /**
1794
- * Reconstruct a {@link ModelView} from an array of crystallographic site
1795
- * labels (`crystLabel`), as produced by {@link ModelView#toLabels}. This
1796
- * is resilient to atom-index reordering across reloads.
1797
- *
1798
- * @param {string[]} labels
1799
- * @return {ModelView}
1800
- */
1801
- viewFromLabels(labels = []) {
1802
- const wanted = new Set(labels);
1803
- const indices = [];
1804
- for (let i = 0; i &lt; this._atom_images.length; ++i) {
1805
- if (wanted.has(this._atom_images[i].crystLabel)) {
1806
- indices.push(i);
1807
- }
1808
- }
1809
- return this.view(indices);
1810
- }
1811
-
1812
- /**
1813
- * Set a property on a series of atom images
1814
- *
1815
- * @private
1816
- * @param {AtomImage[]} aimages List of AtomImages, or their indices
1817
- * @param {String} name Name of the property to set
1818
- * @param {String} value Value to set to the property
1819
- */
1820
- _setAtomsProperty(aimages, name, value) {
1821
-
1822
- // Value can be a single value or an Array
1823
- var isarr = (value instanceof Array);
1824
-
1825
- for (let i = 0; i &lt; aimages.length; ++i) {
1826
- var id = aimages[i];
1827
- if (id instanceof AtomImage)
1828
- id = id.imgIndex;
1829
- this._atom_images[id][name] = isarr ? value[i] : value;
1830
- }
1831
-
1832
- }
1833
-
1834
- /**
1835
- * Set a property on a series of bond images
1836
- *
1837
- * @private
1838
- * @param {BondImage[]} aimages List of BondImages
1839
- * @param {String} name Name of the property to set
1840
- * @param {String} value Value to set to the property
1841
- */
1842
- _setBondsProperty(bimages, name, value) {
1843
-
1844
- // Value can be a single value or an Array
1845
- var isarr = (value instanceof Array);
1846
-
1847
- for (let i = 0; i &lt; bimages.length; ++i) {
1848
- var bimg = bimages[i];
1849
- bimg[name] = isarr ? value[i] : value;
1850
- }
1851
-
1852
- }
1853
-
1854
- // Query functions. These are for internal use. They return the indices of
1855
- // AtomImages in the _atom_images array.
1856
-
1857
- /**
1858
- * @private
1859
- */
1860
- _queryAll() {
1861
- // All atoms
1862
- return _.range(this._atom_images.length);
1863
- }
1864
-
1865
- /**
1866
- * @private
1867
- */
1868
- _queryIndices(indices) {
1869
-
1870
- if (typeof(indices) == 'number') {
1871
- indices = [indices]; // A single index
1872
- }
1873
-
1874
- var scell = this.supercell;
1875
- var n = this.length;
1876
- var scgrid = this._supercell_grid;
1877
-
1878
- var found = _.map(indices, function(i) {
1879
- return _.map(scgrid, function(ijk) {
1880
- return utils.supercellIndex(i, ijk, scell, n);
1881
- });
1882
- });
1883
-
1884
- return _.flatten(found);
1885
- }
1886
-
1887
- /**
1888
- * @private
1889
- */
1890
- _queryElements(elems) {
1891
- if (_.isString(elems)) {
1892
- elems = [elems]; // A single symbol
1893
- }
1894
-
1895
- var indices = _.reduce(this._elems, function(inds, s, i) {
1896
- if (elems.indexOf(s) > -1) {
1897
- inds.push(i);
1898
- }
1899
- return inds;
1900
- }, []);
1901
-
1902
- return this._queryIndices(indices);
1903
- }
1904
-
1905
- /**
1906
- * @private
1907
- */
1908
- _queryLabels(labels) {
1909
- if (_.isString(labels)) {
1910
- labels = [labels]; // A single label
1911
- }
1912
- var indices = _.reduce(this._labels, function(inds, s, i) {
1913
- if (labels.indexOf(s) > -1) {
1914
- inds.push(i);
1915
- }
1916
- return inds;
1917
- }, []);
1918
-
1919
- return this._queryIndices(indices);
1920
- }
1921
-
1922
- /**
1923
- * @private
1924
- */
1925
- _queryCell(ijk) {
1926
-
1927
- // Check if ijk is contained in the supercell's limits
1928
- var ind = _.findIndex(this._supercell_grid, function(x) {
1929
- return _.isEqual(x, ijk);
1930
- });
1931
-
1932
- if (ind &lt; 0) {
1933
- return [];
1934
- }
1935
-
1936
- var scell = this.supercell;
1937
- var n = this.length;
1938
- var found = _.map(_.range(n), function(x) {
1939
- return utils.supercellIndex(x, ijk, scell, n);
1940
- });
1941
-
1942
- return found;
1943
- }
1944
-
1945
- /**
1946
- * @private
1947
- */
1948
- _queryBox(x0, x1) {
1949
-
1950
- if (x0 instanceof AtomImage) {
1951
- x0 = x0.xyz;
1952
- }
1953
- if (x1 instanceof AtomImage) {
1954
- x1 = x1.xyz;
1955
- }
1956
-
1957
- // Box sides?
1958
- var box = _.zip(x0, x1);
1959
- var xmin = _.map(box, _.min);
1960
- var xmax = _.map(box, _.max);
1961
-
1962
- var fxmin;
1963
- var fxmax;
1964
- if (this.periodic) {
1965
- var fx0 = this.absToFrac(x0);
1966
- var fx1 = this.absToFrac(x1);
1967
- var fbox = _.zip(fx0, fx1);
1968
- fxmin = _.map(fbox, _.min);
1969
- fxmax = _.map(fbox, _.max);
1970
- fxmin = _.map(fxmin, Math.floor);
1971
- fxmax = _.map(fxmax, Math.ceil);
1972
-
1973
- // Now add supercell limits
1974
- var scmin = this._supercell_grid[0];
1975
- var scmax = this._supercell_grid[this._supercell_grid.length - 1];
1976
- fxmin = _.zipWith(fxmin, scmin, function(f, s) {
1977
- return Math.max(f, s);
1978
- });
1979
- fxmax = _.zipWith(fxmax, scmax, function(f, s) {
1980
- return Math.min(f, s + 1);
1981
- });
1982
- } else {
1983
- fxmin = [0, 0, 0];
1984
- fxmax = [1, 1, 1];
1985
- }
1986
-
1987
- var found = []
1988
-
1989
- // Now iterate over the cells, and atoms
1990
- for (let i = fxmin[0]; i &lt; fxmax[0]; ++i) {
1991
- for (let j = fxmin[1]; j &lt; fxmax[1]; ++j) {
1992
- for (let k = fxmin[2]; k &lt; fxmax[2]; ++k) {
1993
- // var p0 = this.fracToAbs([i, j, k]);
1994
- for (let a = 0; a &lt; this.length; ++a) {
1995
-
1996
- var ind = utils.supercellIndex(a, [i, j, k], this._supercell,
1997
- this.length);
1998
- var aimg = this._atom_images[ind];
1999
-
2000
- // Is it in the box?
2001
- var isin = _.reduce(aimg.xyz, function(r, x, e) {
2002
- return (r &amp;&amp; (xmin[e] &lt;= x) &amp;&amp; (x &lt;= xmax[e]));
2003
- }, true);
2004
-
2005
- if (isin)
2006
- found.push(ind);
2007
- }
2008
- }
2009
- }
2010
- }
2011
-
2012
- return found;
2013
- }
2014
-
2015
- /**
2016
- * @private
2017
- */
2018
- _querySphere(x0, r) {
2019
-
2020
- if (x0 instanceof AtomImage) {
2021
- x0 = x0.xyz; // Can use an atom as centre
2022
- }
2023
-
2024
- var scell = [1, 1, 1];
2025
- var cell0 = [0, 0, 0];
2026
- var fx0 = this.absToFrac(x0);
2027
-
2028
- if (this.periodic) {
2029
- // Supercell necessary for the search?
2030
- scell = this.minimumSupercell(r);
2031
- cell0 = _.map(fx0, Math.floor);
2032
- }
2033
-
2034
- var fxmin;
2035
- var fxmax;
2036
- if (this.periodic) {
2037
- fxmin = _.zipWith(cell0, scell, function(c0, s) {
2038
- return c0 - (s - 1) / 2;
2039
- });
2040
- fxmax = _.zipWith(cell0, scell, function(c0, s) {
2041
- return c0 + (s + 1) / 2;
2042
- });
2043
-
2044
- // Now add supercell limits
2045
- var scmin = this._supercell_grid[0];
2046
- var scmax = this._supercell_grid[this._supercell_grid.length - 1];
2047
- fxmin = _.zipWith(fxmin, scmin, function(f, s) {
2048
- return Math.max(f, s);
2049
- });
2050
- fxmax = _.zipWith(fxmax, scmax, function(f, s) {
2051
- return Math.min(f, s + 1);
2052
- });
2053
- } else {
2054
- fxmin = [0, 0, 0];
2055
- fxmax = [1, 1, 1];
2056
- }
2057
-
2058
- var found = [];
2059
-
2060
- for (let i = fxmin[0]; i &lt; fxmax[0]; ++i) {
2061
- for (let j = fxmin[1]; j &lt; fxmax[1]; ++j) {
2062
- for (let k = fxmin[2]; k &lt; fxmax[2]; ++k) {
2063
- for (let a = 0; a &lt; this.length; ++a) {
2064
-
2065
- var ind = utils.supercellIndex(a, [i, j, k], this._supercell,
2066
- this.length);
2067
- var aimg = this._atom_images[ind];
2068
-
2069
- // Is it in the sphere?
2070
- var isin = mjs.distance(aimg.xyz, x0) &lt;= r;
2071
-
2072
- if (isin)
2073
- found.push(ind);
2074
- }
2075
- }
2076
- }
2077
- }
2078
-
2079
- return found;
2080
- }
2081
-
2082
- /**
2083
- * @private
2084
- */
2085
- _queryBonded(atoms, distance = 1, exact = false) {
2086
-
2087
- if (atoms instanceof AtomImage || typeof(atoms) == 'number') {
2088
- atoms = [atoms];
2089
- }
2090
- if (atoms instanceof ModelView) {
2091
- atoms = atoms._images;
2092
- }
2093
- if (atoms instanceof Array &amp;&amp; typeof(atoms[0]) == 'number') {
2094
- var imgs = this._atom_images;
2095
- atoms = _.map(atoms, function(i) {
2096
- return imgs[i];
2097
- });
2098
- }
2099
-
2100
- if (distance &lt; 1) {
2101
- return [];
2102
- }
2103
-
2104
- function a2ii(a) {
2105
- return a.imgIndex;
2106
- }
2107
-
2108
- // Find all atoms that are at most [distance] bonds away from the ones
2109
- // passed as argument
2110
-
2111
- var bonded_tree = [atoms]; // We start with distance zero and build up
2112
- var found = [];
2113
-
2114
- for (let d = 1; d &lt;= distance; ++d) {
2115
- var previous = bonded_tree[d - 1];
2116
- var next = [];
2117
- for (let i = 0; i &lt; previous.length; ++i) {
2118
- next = next.concat(previous[i].bondedAtoms);
2119
- }
2120
- bonded_tree.push(next);
2121
- if (!exact) {
2122
- found = found.concat(_.map(next, a2ii));
2123
- } else if (d == distance) {
2124
- found = _.map(next, a2ii);
2125
- }
2126
- }
2127
-
2128
- found = _.uniq(found); // Remove duplicate values
2129
- found = _.difference(found, _.map(bonded_tree[0], function(a) {
2130
- return a.imgIndex;
2131
- })); // Remove the starting atoms
2132
-
2133
- return found;
2134
- }
2135
-
2136
- /**
2137
- * @private
2138
- */
2139
- _queryMolecule(atoms) {
2140
-
2141
- if (atoms instanceof AtomImage || typeof(atoms) == 'number') {
2142
- atoms = [atoms];
2143
- }
2144
- if (atoms instanceof ModelView) {
2145
- atoms = atoms._images;
2146
- }
2147
- if (atoms instanceof Array &amp;&amp; typeof(atoms[0]) == 'number') {
2148
- var imgs = this._atom_images;
2149
- atoms = _.map(atoms, function(i) {
2150
- return imgs[i];
2151
- });
2152
- }
2153
-
2154
- var found = [];
2155
-
2156
- // For each atom, select the whole molecule
2157
- for (let i = 0; i &lt; atoms.length; ++atoms) {
2158
- var a = atoms[i];
2159
-
2160
- var ind = a.index;
2161
- var mol_ind = this._molinds[ind];
2162
- var mol = this._molecules[mol_ind];
2163
-
2164
- // Identify the atom
2165
- var c0 = _.find(mol, function(am) {
2166
- return am.index == ind;
2167
- }).cell;
2168
-
2169
- // Supercell indices?
2170
- for (let j = 0; j &lt; mol.length; ++j) {
2171
- var am = mol[j];
2172
- var cm = mjs.subtract(am.cell, c0);
2173
- var im = am.index;
2174
- var iim = utils.supercellIndex(im, cm, this._supercell, this.length);
2175
- if (iim >= 0 &amp;&amp; iim &lt; this._atom_images.length) {
2176
- found.push(iim);
2177
- }
2178
- }
2179
- }
2180
-
2181
- return found;
2182
-
2183
- }
2184
-
2185
- }
2186
-
2187
- export {
2188
- AtomImage,
2189
- BondImage,
2190
- Model
2191
- }</code></pre></article></section></div></div></div><div class="search-container" id="PkfLWpAbet" style="display:none"><div class="wrapper" id="iCxFxjkHbP"><button class="icon-button search-close-button" id="VjLlGakifb" aria-label="close search"><svg><use xlink:href="#close-icon"></use></svg></button><div class="search-box-c"><svg><use xlink:href="#search-icon"></use></svg> <input type="text" id="vpcKVYIppa" class="search-input" placeholder="Search..." autofocus></div><div class="search-result-c" id="fWwVHRuDuN"><span class="search-result-c-text">Type anything to view search result</span></div></div></div><div class="mobile-menu-icon-container"><button class="icon-button" id="mobile-menu" data-isopen="false" aria-label="menu"><svg><use xlink:href="#menu-icon"></use></svg></button></div><div id="mobile-sidebar" class="mobile-sidebar-container"><div class="mobile-sidebar-wrapper"><div class="mobile-nav-links"></div><div class="mobile-sidebar-items-c"><div class="sidebar-section-title with-arrow" data-isopen="false" id="sidebar-modules"><div>Modules</div><svg><use xlink:href="#down-icon"></use></svg></div><div class="sidebar-section-children-container"><div class="sidebar-section-children"><a href="lib_model.module_js.html">lib/model.js</a></div><div class="sidebar-section-children"><a href="lib_modelview.module_js.html">lib/modelview.js</a></div><div class="sidebar-section-children"><a href="lib_visualizer.module_js.html">lib/visualizer.js</a></div></div><div class="sidebar-section-title with-arrow" data-isopen="false" id="sidebar-classes"><div>Classes</div><svg><use xlink:href="#down-icon"></use></svg></div><div class="sidebar-section-children-container"><div class="sidebar-section-children"><a href="lib_model.module_js-AtomImage.html">AtomImage</a></div><div class="sidebar-section-children"><a href="lib_model.module_js-BondImage.html">BondImage</a></div><div class="sidebar-section-children"><a href="lib_model.module_js-Model.html">Model</a></div><div class="sidebar-section-children"><a href="lib_modelview.module_js-ModelView.html">ModelView</a></div><div class="sidebar-section-children"><a href="lib_visualizer.module_js-CrystVis.html">CrystVis</a></div></div><div class="sidebar-section-title with-arrow" data-isopen="false" id="sidebar-tutorials"><div>Tutorials</div><svg><use xlink:href="#down-icon"></use></svg></div><div class="sidebar-section-children-container"><div class="sidebar-section-children"><a href="tutorial-Events.html">Events</a></div><div class="sidebar-section-children"><a href="tutorial-Queries.html">Queries</a></div><div class="sidebar-section-children"><a href="tutorial-ThreejsMigration.html">ThreejsMigration</a></div></div></div><div class="mobile-navbar-actions"><div class="navbar-right-item"><button class="icon-button search-button" aria-label="open-search"><svg><use xlink:href="#search-icon"></use></svg></button></div><div class="navbar-right-item"><button class="icon-button theme-toggle" aria-label="toggle-theme"><svg><use class="theme-svg-use" xlink:href="#light-theme-icon"></use></svg></button></div><div class="navbar-right-item"><button class="icon-button font-size" aria-label="change-font-size"><svg><use xlink:href="#font-size-icon"></use></svg></button></div></div></div></div><script type="text/javascript" src="scripts/core.min.js"></script><script src="scripts/search.min.js" defer="defer"></script><script src="scripts/third-party/fuse.js" defer="defer"></script><script type="text/javascript">var tocbotInstance=tocbot.init({tocSelector:"#eed4d2a0bfd64539bb9df78095dec881",contentSelector:".main-content",headingSelector:"h1, h2, h3",hasInnerContainers:!0,scrollContainer:".main-content",headingsOffset:130,onClick:bringLinkToView})</script></body></html>