representation.ts 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156
  1. /**
  2. * Copyright (c) 2020 mol* contributors, licensed under MIT, See LICENSE file for more info.
  3. *
  4. * @author Alexander Rose <alexander.rose@weirdbyte.de>
  5. * @author Sebastian Bittrich <sebastian.bittrich@rcsb.org>
  6. */
  7. import { ParamDefinition as PD } from '../../mol-util/param-definition';
  8. import { Vec3, Mat4 } from '../../mol-math/linear-algebra';
  9. import { Representation, RepresentationContext, RepresentationParamsGetter } from '../../mol-repr/representation';
  10. import { Structure } from '../../mol-model/structure';
  11. import { Spheres } from '../../mol-geo/geometry/spheres/spheres';
  12. import { StructureRepresentationProvider, StructureRepresentation, StructureRepresentationStateBuilder } from '../../mol-repr/structure/representation';
  13. import { MembraneOrientation } from './prop';
  14. import { ThemeRegistryContext } from '../../mol-theme/theme';
  15. import { ShapeRepresentation } from '../../mol-repr/shape/representation';
  16. import { Shape } from '../../mol-model/shape';
  17. import { RuntimeContext } from '../../mol-task';
  18. import { Lines } from '../../mol-geo/geometry/lines/lines';
  19. import { Mesh } from '../../mol-geo/geometry/mesh/mesh';
  20. import { LinesBuilder } from '../../mol-geo/geometry/lines/lines-builder';
  21. import { Circle } from '../../mol-geo/primitive/circle';
  22. import { transformPrimitive } from '../../mol-geo/primitive/primitive';
  23. import { MeshBuilder } from '../../mol-geo/geometry/mesh/mesh-builder';
  24. import { MembraneOrientationProvider } from './prop';
  25. import { MarkerActions } from '../../mol-util/marker-action';
  26. import { lociLabel } from '../../mol-theme/label';
  27. import { ColorNames } from '../../mol-util/color/names';
  28. import { CustomProperty } from '../../mol-model-props/common/custom-property';
  29. const SharedParams = {
  30. color: PD.Color(ColorNames.lightgrey),
  31. radiusFactor: PD.Numeric(0.8333, { min: 0.1, max: 3.0, step: 0.01 }, { description: 'Scale the radius of the membrane layer' })
  32. };
  33. const BilayerSpheresParams = {
  34. ...Spheres.Params,
  35. ...SharedParams,
  36. sphereSize: PD.Numeric(1, { min: 0.1, max: 10, step: 0.1 }, { description: 'Size of spheres that represent membrane planes' }),
  37. density: PD.Numeric(1, { min: 0.25, max: 10, step: 0.25 }, { description: 'Distance between spheres'})
  38. };
  39. export type BilayerSpheresParams = typeof BilayerSpheresParams
  40. export type BilayerSpheresProps = PD.Values<BilayerSpheresParams>
  41. const BilayerPlanesParams = {
  42. ...Mesh.Params,
  43. ...SharedParams,
  44. sectorOpacity: PD.Numeric(0.5, { min: 0, max: 1, step: 0.01 }),
  45. };
  46. export type BilayerPlanesParams = typeof BilayerPlanesParams
  47. export type BilayerPlanesProps = PD.Values<BilayerPlanesParams>
  48. const BilayerRimsParams = {
  49. ...Lines.Params,
  50. ...SharedParams,
  51. lineSizeAttenuation: PD.Boolean(true),
  52. linesSize: PD.Numeric(0.3, { min: 0.01, max: 50, step: 0.01 }),
  53. dashedLines: PD.Boolean(true),
  54. };
  55. export type BilayerRimsParams = typeof BilayerRimsParams
  56. export type BilayerRimsProps = PD.Values<BilayerRimsParams>
  57. const MembraneOrientationVisuals = {
  58. 'bilayer-planes': (ctx: RepresentationContext, getParams: RepresentationParamsGetter<MembraneOrientation, BilayerPlanesParams>) => ShapeRepresentation(getBilayerPlanes, Mesh.Utils, { modifyState: s => ({ ...s, markerActions: MarkerActions.Highlighting }), modifyProps: p => ({ ...p, alpha: p.sectorOpacity, ignoreLight: true, doubleSided: false }) }),
  59. 'bilayer-rims': (ctx: RepresentationContext, getParams: RepresentationParamsGetter<MembraneOrientation, BilayerRimsParams>) => ShapeRepresentation(getBilayerRims, Lines.Utils, { modifyState: s => ({ ...s, markerActions: MarkerActions.Highlighting }) })
  60. };
  61. export const MembraneOrientationParams = {
  62. ...BilayerSpheresParams,
  63. ...BilayerPlanesParams,
  64. ...BilayerRimsParams,
  65. visuals: PD.MultiSelect(['bilayer-planes', 'bilayer-rims'], PD.objectToOptions(MembraneOrientationVisuals)),
  66. };
  67. export type MembraneOrientationParams = typeof MembraneOrientationParams
  68. export type MembraneOrientationProps = PD.Values<MembraneOrientationParams>
  69. export function getMembraneOrientationParams(ctx: ThemeRegistryContext, structure: Structure) {
  70. return PD.clone(MembraneOrientationParams);
  71. }
  72. export type MembraneOrientationRepresentation = StructureRepresentation<MembraneOrientationParams>
  73. export function MembraneOrientationRepresentation(ctx: RepresentationContext, getParams: RepresentationParamsGetter<Structure, MembraneOrientationParams>): MembraneOrientationRepresentation {
  74. return Representation.createMulti('Membrane Orientation', ctx, getParams, StructureRepresentationStateBuilder, MembraneOrientationVisuals as unknown as Representation.Def<Structure, MembraneOrientationParams>);
  75. }
  76. export const MembraneOrientationRepresentationProvider = StructureRepresentationProvider({
  77. name: 'membrane-orientation',
  78. label: 'Membrane Orientation',
  79. description: 'Displays a grid of points representing membrane layers.',
  80. factory: MembraneOrientationRepresentation,
  81. getParams: getMembraneOrientationParams,
  82. defaultValues: PD.getDefaultValues(MembraneOrientationParams),
  83. defaultColorTheme: { name: 'shape-group' },
  84. defaultSizeTheme: { name: 'shape-group' },
  85. isApplicable: (structure: Structure) => structure.elementCount > 0,
  86. ensureCustomProperties: {
  87. attach: (ctx: CustomProperty.Context, structure: Structure) => MembraneOrientationProvider.attach(ctx, structure, void 0, true),
  88. detach: (data) => MembraneOrientationProvider.ref(data, false)
  89. }
  90. });
  91. function membraneLabel(data: Structure) {
  92. return `${lociLabel(Structure.Loci(data))} | Membrane Orientation`;
  93. }
  94. function getBilayerRims(ctx: RuntimeContext, data: Structure, props: BilayerRimsProps, shape?: Shape<Lines>): Shape<Lines> {
  95. const { planePoint1: p1, planePoint2: p2, centroid, normalVector: normal, radius } = MembraneOrientationProvider.get(data).value!;
  96. const scaledRadius = props.radiusFactor * radius;
  97. const builder = LinesBuilder.create(128, 64, shape?.geometry);
  98. getLayerCircle(builder, p1, centroid, normal, scaledRadius, props);
  99. getLayerCircle(builder, p2, centroid, normal, scaledRadius, props);
  100. return Shape.create('Bilayer rims', data, builder.getLines(), () => props.color, () => props.linesSize, () => membraneLabel(data));
  101. }
  102. function getLayerCircle(builder: LinesBuilder, p: Vec3, centroid: Vec3, normal: Vec3, radius: number, props: BilayerRimsProps, shape?: Shape<Lines>) {
  103. const circle = getCircle(p, centroid, normal, radius);
  104. const { indices, vertices } = circle;
  105. for (let j = 0, jl = indices.length; j < jl; j += 3) {
  106. if (props.dashedLines && j % 2 === 1) continue; // draw every other segment to get dashes
  107. const start = indices[j] * 3;
  108. const end = indices[j + 1] * 3;
  109. const startX = vertices[start];
  110. const startY = vertices[start + 1];
  111. const startZ = vertices[start + 2];
  112. const endX = vertices[end];
  113. const endY = vertices[end + 1];
  114. const endZ = vertices[end + 2];
  115. builder.add(startX, startY, startZ, endX, endY, endZ, 0);
  116. }
  117. }
  118. const tmpMat = Mat4();
  119. function getCircle(p: Vec3, centroid: Vec3, normal: Vec3, radius: number) {
  120. Mat4.targetTo(tmpMat, p, centroid, normal);
  121. Mat4.setTranslation(tmpMat, p);
  122. Mat4.mul(tmpMat, tmpMat, Mat4.rotX90);
  123. const circle = Circle({ radius, segments: 64 });
  124. return transformPrimitive(circle, tmpMat);
  125. }
  126. function getBilayerPlanes(ctx: RuntimeContext, data: Structure, props: BilayerPlanesProps, shape?: Shape<Mesh>): Shape<Mesh> {
  127. const { planePoint1: p1, planePoint2: p2, centroid, normalVector: normal, radius } = MembraneOrientationProvider.get(data).value!;
  128. const state = MeshBuilder.createState(128, 64, shape && shape.geometry);
  129. const scaledRadius = props.radiusFactor * radius;
  130. getLayerPlane(state, p1, centroid, normal, scaledRadius);
  131. getLayerPlane(state, p2, centroid, normal, scaledRadius);
  132. return Shape.create('Bilayer planes', data, MeshBuilder.getMesh(state), () => props.color, () => 1, () => membraneLabel(data));
  133. }
  134. function getLayerPlane(state: MeshBuilder.State, p: Vec3, centroid: Vec3, normal: Vec3, radius: number) {
  135. const circle = getCircle(p, centroid, normal, radius);
  136. state.currentGroup = 0;
  137. MeshBuilder.addPrimitive(state, Mat4.id, circle);
  138. MeshBuilder.addPrimitiveFlipped(state, Mat4.id, circle);
  139. }