representation.ts 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122
  1. /**
  2. * Copyright (c) 2018 mol* contributors, licensed under MIT, See LICENSE file for more info.
  3. *
  4. * @author Alexander Rose <alexander.rose@weirdbyte.de>
  5. */
  6. import { Task } from 'mol-task'
  7. import { RenderObject, createMeshRenderObject, MeshRenderObject } from 'mol-gl/render-object';
  8. import { Representation, RepresentationContext } from '../representation';
  9. import { Loci, EmptyLoci, isEveryLoci } from 'mol-model/loci';
  10. import { ValueCell } from 'mol-util';
  11. import { Shape } from 'mol-model/shape';
  12. import { OrderedSet, Interval } from 'mol-data/int';
  13. import { ParamDefinition as PD } from 'mol-util/param-definition';
  14. import { Mesh } from 'mol-geo/geometry/mesh/mesh';
  15. import { createIdentityTransform } from 'mol-geo/geometry/transform-data';
  16. import { createRenderableState } from 'mol-geo/geometry/geometry';
  17. import { PickingId } from 'mol-geo/geometry/picking';
  18. import { MarkerAction, applyMarkerAction } from 'mol-geo/geometry/marker-data';
  19. import { LocationIterator } from 'mol-geo/util/location-iterator';
  20. import { ThemeProps, createTheme } from 'mol-theme/theme';
  21. import { BehaviorSubject } from 'rxjs';
  22. export interface ShapeRepresentation<P extends ShapeParams> extends Representation<Shape, P> { }
  23. export const ShapeParams = {
  24. ...Mesh.Params,
  25. // TODO
  26. // colorTheme: PD.Select<ColorThemeName>('Color Theme', '', 'shape-group', ColorThemeOptions)
  27. }
  28. export type ShapeParams = typeof ShapeParams
  29. export function ShapeRepresentation<P extends ShapeParams>(): ShapeRepresentation<P> {
  30. const updated = new BehaviorSubject(0)
  31. const renderObjects: RenderObject[] = []
  32. let _renderObject: MeshRenderObject | undefined
  33. let _shape: Shape
  34. let currentProps: PD.DefaultValues<P> = PD.getDefaultValues(ShapeParams) as PD.DefaultValues<P>
  35. let currentParams: P
  36. function createOrUpdate(ctx: RepresentationContext, props: Partial<PD.DefaultValues<P>> = {}, themeProps: ThemeProps = {}, shape?: Shape) {
  37. currentProps = Object.assign({}, currentProps, props)
  38. if (shape) _shape = shape
  39. return Task.create('ShapeRepresentation.create', async runtime => {
  40. renderObjects.length = 0
  41. if (!_shape) return
  42. const mesh = _shape.mesh
  43. const locationIt = ShapeGroupIterator.fromShape(_shape)
  44. const theme = createTheme(ctx, currentProps, themeProps, {})
  45. const transform = createIdentityTransform()
  46. const values = await Mesh.createValues(runtime, mesh, transform, locationIt, theme, currentProps)
  47. const state = createRenderableState(currentProps)
  48. _renderObject = createMeshRenderObject(values, state)
  49. renderObjects.push(_renderObject)
  50. updated.next(updated.getValue() + 1)
  51. });
  52. }
  53. return {
  54. label: 'Shape mesh',
  55. updated,
  56. get renderObjects () { return renderObjects },
  57. get params () { return currentParams },
  58. get props () { return currentProps },
  59. createOrUpdate,
  60. getLoci(pickingId: PickingId) {
  61. const { objectId, groupId } = pickingId
  62. if (_renderObject && _renderObject.id === objectId) {
  63. return Shape.Loci(_shape, [{ ids: OrderedSet.ofSingleton(groupId) }])
  64. }
  65. return EmptyLoci
  66. },
  67. mark(loci: Loci, action: MarkerAction) {
  68. if (!_renderObject) return false
  69. const { tMarker } = _renderObject.values
  70. let changed = false
  71. if (isEveryLoci(loci)) {
  72. if (applyMarkerAction(tMarker.ref.value.array, 0, _shape.mesh.triangleCount, action)) changed = true
  73. } else if (Shape.isLoci(loci)) {
  74. for (const g of loci.groups) {
  75. if (Interval.is(g.ids)) {
  76. const start = Interval.start(g.ids)
  77. const end = Interval.end(g.ids)
  78. if (applyMarkerAction(tMarker.ref.value.array, start, end, action)) changed = true
  79. } else {
  80. for (let i = 0, _i = g.ids.length; i < _i; i++) {
  81. const idx = g.ids[i];
  82. if (applyMarkerAction(tMarker.ref.value.array, idx, idx + 1, action)) changed = true
  83. }
  84. }
  85. }
  86. }
  87. if (changed) {
  88. ValueCell.update(tMarker, tMarker.ref.value)
  89. }
  90. return changed
  91. },
  92. destroy() {
  93. // TODO
  94. renderObjects.length = 0
  95. _renderObject = undefined
  96. }
  97. }
  98. }
  99. export namespace ShapeGroupIterator {
  100. export function fromShape(shape: Shape): LocationIterator {
  101. const { groupCount } = shape
  102. const instanceCount = 1
  103. const location = Shape.Location(shape)
  104. const getLocation = (groupIndex: number) => {
  105. location.group = groupIndex
  106. return location
  107. }
  108. return LocationIterator(groupCount, instanceCount, getLocation)
  109. }
  110. }