orientation.ts 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139
  1. /**
  2. * Copyright (c) 2019 mol* contributors, licensed under MIT, See LICENSE file for more info.
  3. *
  4. * @author Alexander Rose <alexander.rose@weirdbyte.de>
  5. */
  6. import { Loci } from '../../../mol-model/loci';
  7. import { RuntimeContext } from '../../../mol-task';
  8. import { stringToWords } from '../../../mol-util/string';
  9. import { ParamDefinition as PD } from '../../../mol-util/param-definition';
  10. import { ColorNames } from '../../../mol-util/color/names';
  11. import { ShapeRepresentation } from '../representation';
  12. import { Representation, RepresentationParamsGetter, RepresentationContext } from '../../representation';
  13. import { Shape } from '../../../mol-model/shape';
  14. import { Mesh } from '../../../mol-geo/geometry/mesh/mesh';
  15. import { MeshBuilder } from '../../../mol-geo/geometry/mesh/mesh-builder';
  16. import { PrincipalAxes } from '../../../mol-math/linear-algebra/matrix/principal-axes';
  17. import { lociLabel } from '../../../mol-theme/label';
  18. import { addAxes } from '../../../mol-geo/geometry/mesh/builder/axes';
  19. import { addOrientedBox } from '../../../mol-geo/geometry/mesh/builder/box';
  20. import { addEllipsoid } from '../../../mol-geo/geometry/mesh/builder/ellipsoid';
  21. import { Axes3D } from '../../../mol-math/geometry';
  22. import { Vec3 } from '../../../mol-math/linear-algebra';
  23. export interface OrientationData {
  24. loci: Loci
  25. }
  26. const SharedParams = {
  27. color: PD.Color(ColorNames.orange),
  28. scale: PD.Numeric(2, { min: 0.1, max: 10, step: 0.1 })
  29. }
  30. const AxesParams = {
  31. ...Mesh.Params,
  32. ...SharedParams
  33. }
  34. type AxesParams = typeof AxesParams
  35. const BoxParams = {
  36. ...Mesh.Params,
  37. ...SharedParams
  38. }
  39. type BoxParams = typeof BoxParams
  40. const EllipsoidParams = {
  41. ...Mesh.Params,
  42. ...SharedParams
  43. }
  44. type EllipsoidParams = typeof EllipsoidParams
  45. const OrientationVisuals = {
  46. 'axes': (ctx: RepresentationContext, getParams: RepresentationParamsGetter<OrientationData, AxesParams>) => ShapeRepresentation(getAxesShape, Mesh.Utils),
  47. 'box': (ctx: RepresentationContext, getParams: RepresentationParamsGetter<OrientationData, BoxParams>) => ShapeRepresentation(getBoxShape, Mesh.Utils),
  48. 'ellipsoid': (ctx: RepresentationContext, getParams: RepresentationParamsGetter<OrientationData, EllipsoidParams>) => ShapeRepresentation(getEllipsoidShape, Mesh.Utils),
  49. }
  50. type OrientationVisualName = keyof typeof OrientationVisuals
  51. const OrientationVisualOptions = Object.keys(OrientationVisuals).map(name => [name, stringToWords(name)] as [OrientationVisualName, string])
  52. export const OrientationParams = {
  53. ...AxesParams,
  54. ...BoxParams,
  55. visuals: PD.MultiSelect<OrientationVisualName>(['box'], OrientationVisualOptions),
  56. color: PD.Color(ColorNames.orange),
  57. scale: PD.Numeric(2, { min: 0.1, max: 5, step: 0.1 })
  58. }
  59. export type OrientationParams = typeof OrientationParams
  60. export type OrientationProps = PD.Values<OrientationParams>
  61. //
  62. function buildAxesMesh(principalAxes: PrincipalAxes, props: OrientationProps, mesh?: Mesh): Mesh {
  63. const state = MeshBuilder.createState(256, 128, mesh)
  64. state.currentGroup = 1
  65. addAxes(state, principalAxes.momentsAxes, props.scale, 2, 20)
  66. return MeshBuilder.getMesh(state)
  67. }
  68. function getAxesShape(ctx: RuntimeContext, data: OrientationData, props: OrientationProps, shape?: Shape<Mesh>) {
  69. const label = lociLabel(data.loci, { countsOnly: true })
  70. const principalAxes = Loci.getPrincipalAxes(data.loci)
  71. const mesh = principalAxes ? buildAxesMesh(principalAxes, props, shape && shape.geometry) : Mesh.createEmpty(shape && shape.geometry);
  72. const getLabel = function (groupId: number ) {
  73. return `Principal Axes of ${label}`
  74. }
  75. return Shape.create('Principal Axes', data, mesh, () => props.color, () => 1, getLabel)
  76. }
  77. //
  78. function buildBoxMesh(principalAxes: PrincipalAxes, props: OrientationProps, mesh?: Mesh): Mesh {
  79. const state = MeshBuilder.createState(256, 128, mesh)
  80. state.currentGroup = 1
  81. addOrientedBox(state, principalAxes.boxAxes, props.scale, 2, 20)
  82. return MeshBuilder.getMesh(state)
  83. }
  84. function getBoxShape(ctx: RuntimeContext, data: OrientationData, props: OrientationProps, shape?: Shape<Mesh>) {
  85. const label = lociLabel(data.loci, { countsOnly: true })
  86. const principalAxes = Loci.getPrincipalAxes(data.loci)
  87. const mesh = principalAxes ? buildBoxMesh(principalAxes, props, shape && shape.geometry) : Mesh.createEmpty(shape && shape.geometry);
  88. const getLabel = function (groupId: number ) {
  89. return `Oriented Box of ${label}`
  90. }
  91. return Shape.create('Oriented Box', data, mesh, () => props.color, () => 1, getLabel)
  92. }
  93. //
  94. function buildEllipsoidMesh(principalAxes: PrincipalAxes, props: OrientationProps, mesh?: Mesh): Mesh {
  95. const state = MeshBuilder.createState(256, 128, mesh)
  96. const axes = principalAxes.boxAxes
  97. const { origin, dirA, dirB } = axes
  98. const size = Axes3D.size(Vec3(), axes)
  99. Vec3.scale(size, size, 0.5)
  100. const radiusScale = Vec3.create(size[2], size[1], size[0])
  101. state.currentGroup = 1
  102. addEllipsoid(state, origin, dirA, dirB, radiusScale, 2)
  103. return MeshBuilder.getMesh(state)
  104. }
  105. function getEllipsoidShape(ctx: RuntimeContext, data: OrientationData, props: OrientationProps, shape?: Shape<Mesh>) {
  106. const label = lociLabel(data.loci, { countsOnly: true })
  107. const principalAxes = Loci.getPrincipalAxes(data.loci)
  108. const mesh = principalAxes ? buildEllipsoidMesh(principalAxes, props, shape && shape.geometry) : Mesh.createEmpty(shape && shape.geometry);
  109. const getLabel = function (groupId: number ) {
  110. return `Ellipsoid of ${label}`
  111. }
  112. return Shape.create('Ellipsoid', data, mesh, () => props.color, () => 1, getLabel)
  113. }
  114. //
  115. export type OrientationRepresentation = Representation<OrientationData, OrientationParams>
  116. export function OrientationRepresentation(ctx: RepresentationContext, getParams: RepresentationParamsGetter<OrientationData, OrientationParams>): OrientationRepresentation {
  117. return Representation.createMulti('Orientation', ctx, getParams, Representation.StateBuilder, OrientationVisuals as unknown as Representation.Def<OrientationData, OrientationParams>)
  118. }