representation.ts 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129
  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 { createTheme } from 'mol-theme/theme';
  21. import { Subject } 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. let version = 0
  31. const updated = new Subject<number>()
  32. const renderObjects: RenderObject[] = []
  33. let _renderObject: MeshRenderObject | undefined
  34. let _shape: Shape
  35. let currentProps: PD.Values<P> = PD.getDefaultValues(ShapeParams) as PD.Values<P>
  36. let currentParams: P
  37. function createOrUpdate(ctx: RepresentationContext, props: Partial<PD.Values<P>> = {}, shape?: Shape) {
  38. currentProps = Object.assign({}, currentProps, props)
  39. if (shape) _shape = shape
  40. return Task.create('ShapeRepresentation.create', async runtime => {
  41. renderObjects.length = 0
  42. if (!_shape) return
  43. const mesh = _shape.mesh
  44. const locationIt = ShapeGroupIterator.fromShape(_shape)
  45. const theme = createTheme(ctx, currentProps, {})
  46. const transform = createIdentityTransform()
  47. const values = await Mesh.createValues(runtime, mesh, transform, locationIt, theme, currentProps)
  48. const state = createRenderableState(currentProps)
  49. _renderObject = createMeshRenderObject(values, state)
  50. renderObjects.push(_renderObject)
  51. updated.next(version++)
  52. });
  53. }
  54. return {
  55. label: 'Shape mesh',
  56. updated,
  57. get renderObjects () { return renderObjects },
  58. get params () { return currentParams },
  59. get props () { return currentProps },
  60. createOrUpdate,
  61. getLoci(pickingId: PickingId) {
  62. const { objectId, groupId } = pickingId
  63. if (_renderObject && _renderObject.id === objectId) {
  64. return Shape.Loci(_shape, [{ ids: OrderedSet.ofSingleton(groupId) }])
  65. }
  66. return EmptyLoci
  67. },
  68. mark(loci: Loci, action: MarkerAction) {
  69. if (!_renderObject) return false
  70. const { tMarker } = _renderObject.values
  71. let changed = false
  72. if (isEveryLoci(loci)) {
  73. if (applyMarkerAction(tMarker.ref.value.array, 0, _shape.mesh.triangleCount, action)) changed = true
  74. } else if (Shape.isLoci(loci)) {
  75. for (const g of loci.groups) {
  76. if (Interval.is(g.ids)) {
  77. const start = Interval.start(g.ids)
  78. const end = Interval.end(g.ids)
  79. if (applyMarkerAction(tMarker.ref.value.array, start, end, action)) changed = true
  80. } else {
  81. for (let i = 0, _i = g.ids.length; i < _i; i++) {
  82. const idx = g.ids[i];
  83. if (applyMarkerAction(tMarker.ref.value.array, idx, idx + 1, action)) changed = true
  84. }
  85. }
  86. }
  87. }
  88. if (changed) {
  89. ValueCell.update(tMarker, tMarker.ref.value)
  90. }
  91. return changed
  92. },
  93. setVisibility(value: boolean) {
  94. renderObjects.forEach(ro => ro.state.visible = value)
  95. },
  96. setPickable(value: boolean) {
  97. renderObjects.forEach(ro => ro.state.pickable = value)
  98. },
  99. destroy() {
  100. // TODO
  101. renderObjects.length = 0
  102. _renderObject = undefined
  103. }
  104. }
  105. }
  106. export namespace ShapeGroupIterator {
  107. export function fromShape(shape: Shape): LocationIterator {
  108. const { groupCount } = shape
  109. const instanceCount = 1
  110. const location = Shape.Location(shape)
  111. const getLocation = (groupIndex: number) => {
  112. location.group = groupIndex
  113. return location
  114. }
  115. return LocationIterator(groupCount, instanceCount, getLocation)
  116. }
  117. }