NGL@1.0.0-beta.7 Home Manual Reference Source Gallery

src/symmetry/unitcell.js

  1. /**
  2. * @file Unitcell
  3. * @author Alexander Rose <alexander.rose@weirdbyte.de>
  4. * @private
  5. */
  6.  
  7. import { Color, Vector3, Matrix4 } from '../../lib/three.es6.js'
  8.  
  9. import { defaults } from '../utils.js'
  10. import { degToRad } from '../math/math-utils.js'
  11. import {
  12. uniformArray, uniformArray3, centerArray3
  13. } from '../math/array-utils.js'
  14. import { UnitcellPicker } from '../utils/picker.js'
  15.  
  16. /**
  17. * Unitcell class
  18. */
  19. class Unitcell {
  20. /**
  21. * @param {Object} params - unitcell parameters
  22. * @param {Number} params.a - length a
  23. * @param {Number} params.b - length b
  24. * @param {Number} params.c - length c
  25. * @param {Number} params.alpha - angle alpha
  26. * @param {Number} params.beta - angle beta
  27. * @param {Number} params.gamma - angle gamma
  28. * @param {String} params.spacegroup - spacegroup
  29. * @param {Matrix4} [params.cartToFrac] - transformation matrix from
  30. * cartesian to fractional coordinates
  31. * @param {Matrix4} [params.scale] - alias for `params.cartToFrac`
  32. */
  33. constructor (params) {
  34. const p = params || {}
  35.  
  36. /**
  37. * @type {Number}
  38. */
  39. this.a = p.a || 1
  40. /**
  41. * @type {Number}
  42. */
  43. this.b = p.b || 1
  44. /**
  45. * @type {Number}
  46. */
  47. this.c = p.c || 1
  48.  
  49. /**
  50. * @type {Number}
  51. */
  52. this.alpha = p.alpha || 90
  53. /**
  54. * @type {Number}
  55. */
  56. this.beta = p.beta || 90
  57. /**
  58. * @type {Number}
  59. */
  60. this.gamma = p.gamma || 90
  61.  
  62. /**
  63. * @type {String}
  64. */
  65. this.spacegroup = p.spacegroup || 'P 1'
  66. /**
  67. * @type {Matrix4}
  68. */
  69. this.cartToFrac = p.cartToFrac || p.scale
  70. /**
  71. * @type {Matrix4}
  72. */
  73. this.fracToCart = new Matrix4()
  74.  
  75. //
  76.  
  77. const alphaRad = degToRad(this.alpha)
  78. const betaRad = degToRad(this.beta)
  79. const gammaRad = degToRad(this.gamma)
  80. const cosAlpha = Math.cos(alphaRad)
  81. const cosBeta = Math.cos(betaRad)
  82. const cosGamma = Math.cos(gammaRad)
  83. const sinBeta = Math.sin(betaRad)
  84. const sinGamma = Math.sin(gammaRad)
  85.  
  86. /**
  87. * @type {Number}
  88. */
  89. this.volume = (
  90. this.a * this.b * this.c *
  91. Math.sqrt(
  92. 1 - cosAlpha * cosAlpha - cosBeta * cosBeta - cosGamma * cosGamma +
  93. 2.0 * cosAlpha * cosBeta * cosGamma
  94. )
  95. )
  96.  
  97. //
  98.  
  99. if (this.cartToFrac === undefined) {
  100. // https://github.com/biojava/biojava/blob/master/biojava-structure/src/main/java/org/biojava/nbio/structure/xtal/CrystalCell.java
  101.  
  102. const cStar = (this.a * this.b * sinGamma) / this.volume
  103. const cosAlphaStar = (
  104. (cosBeta * cosGamma - cosAlpha) / (sinBeta * sinGamma)
  105. )
  106.  
  107. this.fracToCart.set(
  108. this.a, 0, 0, 0,
  109. this.b * cosGamma, this.b * sinGamma, 0, 0,
  110. this.c * cosBeta, -this.c * sinBeta * cosAlphaStar, 1.0 / cStar, 0,
  111. 0, 0, 0, 1
  112. ).transpose()
  113. this.cartToFrac = new Matrix4().getInverse(this.fracToCart)
  114. } else {
  115. this.fracToCart.getInverse(this.cartToFrac)
  116. }
  117. }
  118.  
  119. getPosition (structure) {
  120. const vertexPosition = new Float32Array(3 * 8)
  121.  
  122. const uc = structure.unitcell
  123. const centerFrac = structure.center.clone()
  124. .applyMatrix4(uc.cartToFrac)
  125. .floor().multiplyScalar(2).addScalar(1)
  126. const v = new Vector3()
  127.  
  128. let cornerOffset = 0
  129. function addCorner (x, y, z) {
  130. v.set(x, y, z)
  131. .multiply(centerFrac)
  132. .applyMatrix4(uc.fracToCart)
  133. .toArray(vertexPosition, cornerOffset)
  134. cornerOffset += 3
  135. }
  136. addCorner(0, 0, 0)
  137. addCorner(1, 0, 0)
  138. addCorner(0, 1, 0)
  139. addCorner(0, 0, 1)
  140. addCorner(1, 1, 0)
  141. addCorner(1, 0, 1)
  142. addCorner(0, 1, 1)
  143. addCorner(1, 1, 1)
  144.  
  145. return vertexPosition
  146. }
  147.  
  148. getCenter (structure) {
  149. return centerArray3(this.getPosition(structure))
  150. }
  151.  
  152. getData (structure, params) {
  153. const p = params || {}
  154. const colorValue = defaults(p.colorValue, 'orange')
  155. const radius = defaults(p.radius, Math.cbrt(this.volume) / 200)
  156.  
  157. const c = new Color(colorValue)
  158. const v = new Vector3()
  159.  
  160. const vertexPosition = this.getPosition(structure)
  161. const vertexColor = uniformArray3(8, c.r, c.g, c.b)
  162. const vertexRadius = uniformArray(8, radius)
  163.  
  164. const edgePosition1 = new Float32Array(3 * 12)
  165. const edgePosition2 = new Float32Array(3 * 12)
  166. const edgeColor = uniformArray3(12, c.r, c.g, c.b)
  167. const edgeRadius = uniformArray(12, radius)
  168.  
  169. let edgeOffset = 0
  170. function addEdge (a, b) {
  171. v.fromArray(vertexPosition, a * 3)
  172. .toArray(edgePosition1, edgeOffset)
  173. v.fromArray(vertexPosition, b * 3)
  174. .toArray(edgePosition2, edgeOffset)
  175. edgeOffset += 3
  176. }
  177. addEdge(0, 1)
  178. addEdge(0, 2)
  179. addEdge(0, 3)
  180. addEdge(1, 4)
  181. addEdge(1, 5)
  182. addEdge(2, 6)
  183. addEdge(3, 5)
  184. addEdge(4, 7)
  185. addEdge(5, 7)
  186. addEdge(2, 4)
  187. addEdge(7, 6)
  188. addEdge(3, 6)
  189.  
  190. const picker = new UnitcellPicker(this, structure)
  191.  
  192. return {
  193. vertex: {
  194. position: vertexPosition,
  195. color: vertexColor,
  196. radius: vertexRadius,
  197. picking: picker
  198. },
  199. edge: {
  200. position1: edgePosition1,
  201. position2: edgePosition2,
  202. color: edgeColor,
  203. color2: edgeColor,
  204. radius: edgeRadius,
  205. picking: picker
  206. }
  207. }
  208. }
  209. }
  210.  
  211. export default Unitcell