unitcell.ts 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120
  1. /**
  2. * Copyright (c) 2019-2020 mol* contributors, licensed under MIT, See LICENSE file for more info.
  3. *
  4. * @author Alexander Rose <alexander.rose@weirdbyte.de>
  5. */
  6. import { Model, Symmetry } from '../../../mol-model/structure';
  7. import { ShapeRepresentation } from '../representation';
  8. import { Shape } from '../../../mol-model/shape';
  9. import { ColorNames } from '../../../mol-util/color/names';
  10. import { RuntimeContext } from '../../../mol-task';
  11. import { ParamDefinition as PD } from '../../../mol-util/param-definition';
  12. import { Mesh } from '../../../mol-geo/geometry/mesh/mesh';
  13. import { MeshBuilder } from '../../../mol-geo/geometry/mesh/mesh-builder';
  14. import { BoxCage } from '../../../mol-geo/primitive/box';
  15. import { Mat4, Vec3 } from '../../../mol-math/linear-algebra';
  16. import { transformCage, cloneCage } from '../../../mol-geo/primitive/cage';
  17. import { radToDeg } from '../../../mol-math/misc';
  18. import { Sphere3D } from '../../../mol-math/geometry';
  19. import { RepresentationParamsGetter, Representation, RepresentationContext } from '../../representation';
  20. const translate05 = Mat4.fromTranslation(Mat4(), Vec3.create(0.5, 0.5, 0.5))
  21. const unitCage = transformCage(cloneCage(BoxCage()), translate05)
  22. const tmpRef = Vec3()
  23. const tmpTranslate = Mat4()
  24. interface UnitcellData {
  25. symmetry: Symmetry
  26. ref: Vec3
  27. }
  28. const CellParams = {
  29. ...Mesh.Params,
  30. cellColor: PD.Color(ColorNames.orange),
  31. cellScale: PD.Numeric(2, { min: 0.1, max: 5, step: 0.1 })
  32. }
  33. type MeshParams = typeof CellParams
  34. const UnitcellVisuals = {
  35. 'mesh': (ctx: RepresentationContext, getParams: RepresentationParamsGetter<UnitcellData, MeshParams>) => ShapeRepresentation(getUnitcellShape, Mesh.Utils),
  36. }
  37. export const UnitcellParams = {
  38. ...CellParams
  39. }
  40. export type UnitcellParams = typeof UnitcellParams
  41. export type UnitcellProps = PD.Values<UnitcellParams>
  42. function getUnitcellMesh(data: UnitcellData, props: UnitcellProps, mesh?: Mesh) {
  43. const state = MeshBuilder.createState(256, 128, mesh)
  44. const { fromFractional } = data.symmetry.spacegroup.cell
  45. Vec3.floor(tmpRef, data.ref)
  46. Mat4.fromTranslation(tmpTranslate, tmpRef)
  47. const cellCage = transformCage(cloneCage(unitCage), tmpTranslate)
  48. const radius = (Math.cbrt(data.symmetry.spacegroup.cell.volume) / 300) * props.cellScale
  49. state.currentGroup = 1
  50. MeshBuilder.addCage(state, fromFractional, cellCage, radius, 2, 20)
  51. const cpA = Vec3.create(0, 0, 0)
  52. Vec3.transformMat4(cpA, Vec3.add(cpA, cpA, tmpRef), fromFractional)
  53. const cpB = Vec3.create(1, 1, 1)
  54. Vec3.transformMat4(cpB, Vec3.add(cpB, cpB, tmpRef), fromFractional)
  55. const cpC = Vec3.create(1, 0, 0)
  56. Vec3.transformMat4(cpC, Vec3.add(cpC, cpC, tmpRef), fromFractional)
  57. const cpD = Vec3.create(0, 1, 1)
  58. Vec3.transformMat4(cpD, Vec3.add(cpD, cpD, tmpRef), fromFractional)
  59. const center = Vec3()
  60. Vec3.add(center, cpA, cpB)
  61. Vec3.scale(center, center, 0.5)
  62. const d = Math.max(Vec3.distance(cpA, cpB), Vec3.distance(cpC, cpD))
  63. const sphere = Sphere3D.create(center, d / 2 + radius)
  64. const m = MeshBuilder.getMesh(state)
  65. m.setBoundingSphere(sphere)
  66. return m
  67. }
  68. function getUnitcellLabel(data: UnitcellData) {
  69. const { cell, name, num } = data.symmetry.spacegroup
  70. const { size, anglesInRadians } = cell
  71. const a = size[0].toFixed(2)
  72. const b = size[1].toFixed(2)
  73. const c = size[2].toFixed(2)
  74. const alpha = radToDeg(anglesInRadians[0]).toFixed(2)
  75. const beta = radToDeg(anglesInRadians[1]).toFixed(2)
  76. const gamma = radToDeg(anglesInRadians[2]).toFixed(2)
  77. const label: string[] = []
  78. // name
  79. label.push(`${name} #${num}`)
  80. // sizes
  81. label.push(`${a}\u00D7${b}\u00D7${c} \u212B`)
  82. // angles
  83. label.push(`\u03b1=${alpha}\u00B0 \u03b2=${beta}\u00B0 \u03b3=${gamma}\u00B0`)
  84. return label.join(' | ')
  85. }
  86. function getUnitcellShape(ctx: RuntimeContext, data: UnitcellData, props: UnitcellProps, shape?: Shape<Mesh>) {
  87. const geo = getUnitcellMesh(data, props, shape && shape.geometry);
  88. const label = getUnitcellLabel(data)
  89. return Shape.create('Unitcell', data, geo, () => props.cellColor, () => 1, () => label)
  90. }
  91. //
  92. export function getUnitcellData(model: Model, symmetry: Symmetry) {
  93. return {
  94. symmetry,
  95. ref: Vec3.transformMat4(Vec3(), Model.getCenter(model), symmetry.spacegroup.cell.toFractional)
  96. }
  97. }
  98. export type UnitcellRepresentation = Representation<UnitcellData, UnitcellParams>
  99. export function UnitcellRepresentation(ctx: RepresentationContext, getParams: RepresentationParamsGetter<UnitcellData, UnitcellParams>): UnitcellRepresentation {
  100. return Representation.createMulti('Unitcell', ctx, getParams, Representation.StateBuilder, UnitcellVisuals as unknown as Representation.Def<UnitcellData, UnitcellParams>)
  101. }