representation.ts 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507
  1. /**
  2. * Copyright (c) 2018-2019 mol* contributors, licensed under MIT, See LICENSE file for more info.
  3. *
  4. * @author David Sehnal <david.sehnal@gmail.com>
  5. * @author Alexander Rose <alexander.rose@weirdbyte.de>
  6. */
  7. import { Structure } from 'mol-model/structure';
  8. import { VolumeData, VolumeIsoValue } from 'mol-model/volume';
  9. import { PluginContext } from 'mol-plugin/context';
  10. import { RepresentationProvider } from 'mol-repr/representation';
  11. import { BuiltInStructureRepresentationsName } from 'mol-repr/structure/registry';
  12. import { StructureParams } from 'mol-repr/structure/representation';
  13. import { BuiltInVolumeRepresentationsName } from 'mol-repr/volume/registry';
  14. import { VolumeParams } from 'mol-repr/volume/representation';
  15. import { StateTransformer } from 'mol-state';
  16. import { Task } from 'mol-task';
  17. import { BuiltInColorThemeName, ColorTheme } from 'mol-theme/color';
  18. import { BuiltInSizeThemeName, SizeTheme } from 'mol-theme/size';
  19. import { createTheme, ThemeRegistryContext } from 'mol-theme/theme';
  20. import { ParamDefinition as PD } from 'mol-util/param-definition';
  21. import { PluginStateObject as SO, PluginStateTransform } from '../objects';
  22. import { Text } from 'mol-geo/geometry/text/text';
  23. import { ColorNames } from 'mol-util/color/tables';
  24. import { getLabelRepresentation } from 'mol-plugin/util/structure-labels';
  25. import { ShapeRepresentation } from 'mol-repr/shape/representation';
  26. import { StructureUnitTransforms } from 'mol-model/structure/structure/util/unit-transforms';
  27. import { unwindStructureAssembly, explodeStructure, getStructureOverpaint } from '../animation/helpers';
  28. import { Color } from 'mol-util/color';
  29. import { Overpaint } from 'mol-theme/overpaint';
  30. import { BaseGeometry } from 'mol-geo/geometry/base';
  31. export { StructureRepresentation3D }
  32. export { StructureRepresentation3DHelpers }
  33. export { StructureLabels3D}
  34. export { ExplodeStructureRepresentation3D }
  35. export { UnwindStructureAssemblyRepresentation3D }
  36. export { OverpaintStructureRepresentation3D as ColorStructureRepresentation3D }
  37. export { VolumeRepresentation3D }
  38. namespace StructureRepresentation3DHelpers {
  39. export function getDefaultParams(ctx: PluginContext, name: BuiltInStructureRepresentationsName, structure: Structure, structureParams?: Partial<PD.Values<StructureParams>>): StateTransformer.Params<StructureRepresentation3D> {
  40. const type = ctx.structureRepresentation.registry.get(name);
  41. const themeDataCtx = { structure };
  42. const colorParams = ctx.structureRepresentation.themeCtx.colorThemeRegistry.get(type.defaultColorTheme).getParams(themeDataCtx);
  43. const sizeParams = ctx.structureRepresentation.themeCtx.sizeThemeRegistry.get(type.defaultSizeTheme).getParams(themeDataCtx)
  44. const structureDefaultParams = PD.getDefaultValues(type.getParams(ctx.structureRepresentation.themeCtx, structure))
  45. return ({
  46. type: { name, params: structureParams ? { ...structureDefaultParams, ...structureParams } : structureDefaultParams },
  47. colorTheme: { name: type.defaultColorTheme, params: PD.getDefaultValues(colorParams) },
  48. sizeTheme: { name: type.defaultSizeTheme, params: PD.getDefaultValues(sizeParams) }
  49. })
  50. }
  51. export function createParams<R extends RepresentationProvider<Structure, any, any>, C extends ColorTheme.Provider<any>, S extends SizeTheme.Provider<any>>(
  52. ctx: PluginContext, structure: Structure, params: {
  53. repr?: R | [R, (r: R, ctx: ThemeRegistryContext, s: Structure) => RepresentationProvider.ParamValues<R>],
  54. color?: C | [C, (c: C, ctx: ThemeRegistryContext) => ColorTheme.ParamValues<C>],
  55. size?: S | [S, (c: S, ctx: ThemeRegistryContext) => SizeTheme.ParamValues<S>]
  56. }): StateTransformer.Params<StructureRepresentation3D> {
  57. const themeCtx = ctx.structureRepresentation.themeCtx
  58. const repr = params.repr
  59. ? params.repr instanceof Array ? params.repr[0] : params.repr
  60. : ctx.structureRepresentation.registry.default.provider;
  61. const reprParams = params.repr instanceof Array
  62. ? params.repr[1](repr as R, themeCtx, structure)
  63. : PD.getDefaultValues(repr.getParams(themeCtx, structure));
  64. const color = params.color
  65. ? params.color instanceof Array ? params.color[0] : params.color
  66. : themeCtx.colorThemeRegistry.get(repr.defaultColorTheme);
  67. const colorParams = params.color instanceof Array
  68. ? params.color[1](color as C, themeCtx)
  69. : PD.getDefaultValues(color.getParams(themeCtx));
  70. const size = params.size
  71. ? params.size instanceof Array ? params.size[0] : params.size
  72. : themeCtx.sizeThemeRegistry.get(repr.defaultSizeTheme);
  73. const sizeParams = params.size instanceof Array
  74. ? params.size[1](size as S, themeCtx)
  75. : PD.getDefaultValues(size.getParams(themeCtx));
  76. return ({
  77. type: { name: ctx.structureRepresentation.registry.getName(repr), params: reprParams },
  78. colorTheme: { name: themeCtx.colorThemeRegistry.getName(color), params: colorParams },
  79. sizeTheme: { name: themeCtx.sizeThemeRegistry.getName(size), params: sizeParams }
  80. })
  81. }
  82. export function getDefaultParamsWithTheme(ctx: PluginContext, reprName: BuiltInStructureRepresentationsName, colorName: BuiltInColorThemeName | undefined, structure: Structure, structureParams?: Partial<PD.Values<StructureParams>>): StateTransformer.Params<StructureRepresentation3D> {
  83. const type = ctx.structureRepresentation.registry.get(reprName);
  84. const themeDataCtx = { structure };
  85. const color = colorName || type.defaultColorTheme;
  86. const colorParams = ctx.structureRepresentation.themeCtx.colorThemeRegistry.get(color).getParams(themeDataCtx);
  87. const sizeParams = ctx.structureRepresentation.themeCtx.sizeThemeRegistry.get(type.defaultSizeTheme).getParams(themeDataCtx)
  88. const structureDefaultParams = PD.getDefaultValues(type.getParams(ctx.structureRepresentation.themeCtx, structure))
  89. return ({
  90. type: { name: reprName, params: structureParams ? { ...structureDefaultParams, ...structureParams } : structureDefaultParams },
  91. colorTheme: { name: color, params: PD.getDefaultValues(colorParams) },
  92. sizeTheme: { name: type.defaultSizeTheme, params: PD.getDefaultValues(sizeParams) }
  93. })
  94. }
  95. export function getDefaultParamsStatic(ctx: PluginContext, name: BuiltInStructureRepresentationsName, structureParams?: Partial<PD.Values<StructureParams>>): StateTransformer.Params<StructureRepresentation3D> {
  96. const type = ctx.structureRepresentation.registry.get(name);
  97. const colorParams = ctx.structureRepresentation.themeCtx.colorThemeRegistry.get(type.defaultColorTheme).defaultValues;
  98. const sizeParams = ctx.structureRepresentation.themeCtx.sizeThemeRegistry.get(type.defaultSizeTheme).defaultValues
  99. return ({
  100. type: { name, params: structureParams ? { ...type.defaultValues, ...structureParams } : type.defaultValues },
  101. colorTheme: { name: type.defaultColorTheme, params: colorParams },
  102. sizeTheme: { name: type.defaultSizeTheme, params: sizeParams }
  103. })
  104. }
  105. }
  106. type StructureRepresentation3D = typeof StructureRepresentation3D
  107. const StructureRepresentation3D = PluginStateTransform.BuiltIn({
  108. name: 'structure-representation-3d',
  109. display: '3D Representation',
  110. from: SO.Molecule.Structure,
  111. to: SO.Molecule.Structure.Representation3D,
  112. params: (a, ctx: PluginContext) => {
  113. const { registry, themeCtx } = ctx.structureRepresentation
  114. const type = registry.get(registry.default.name);
  115. if (!a) {
  116. return {
  117. type: PD.Mapped<any>(
  118. registry.default.name,
  119. registry.types,
  120. name => PD.Group<any>(registry.get(name).getParams(themeCtx, Structure.Empty))),
  121. colorTheme: PD.Mapped<any>(
  122. type.defaultColorTheme,
  123. themeCtx.colorThemeRegistry.types,
  124. name => PD.Group<any>(themeCtx.colorThemeRegistry.get(name).getParams({ structure: Structure.Empty }))
  125. ),
  126. sizeTheme: PD.Mapped<any>(
  127. type.defaultSizeTheme,
  128. themeCtx.sizeThemeRegistry.types,
  129. name => PD.Group<any>(themeCtx.sizeThemeRegistry.get(name).getParams({ structure: Structure.Empty }))
  130. )
  131. }
  132. }
  133. const dataCtx = { structure: a.data }
  134. return ({
  135. type: PD.Mapped<any>(
  136. registry.default.name,
  137. registry.types,
  138. name => PD.Group<any>(registry.get(name).getParams(themeCtx, a.data))),
  139. colorTheme: PD.Mapped<any>(
  140. type.defaultColorTheme,
  141. themeCtx.colorThemeRegistry.getApplicableTypes(dataCtx),
  142. name => PD.Group<any>(themeCtx.colorThemeRegistry.get(name).getParams(dataCtx))
  143. ),
  144. sizeTheme: PD.Mapped<any>(
  145. type.defaultSizeTheme,
  146. themeCtx.sizeThemeRegistry.types,
  147. name => PD.Group<any>(themeCtx.sizeThemeRegistry.get(name).getParams(dataCtx))
  148. )
  149. })
  150. }
  151. })({
  152. canAutoUpdate({ a, oldParams, newParams }) {
  153. // TODO: other criteria as well?
  154. return a.data.elementCount < 10000 || oldParams.type.name === newParams.type.name;
  155. },
  156. apply({ a, params }, plugin: PluginContext) {
  157. return Task.create('Structure Representation', async ctx => {
  158. const provider = plugin.structureRepresentation.registry.get(params.type.name)
  159. const props = params.type.params || {}
  160. const repr = provider.factory({ webgl: plugin.canvas3d.webgl, ...plugin.structureRepresentation.themeCtx }, provider.getParams)
  161. repr.setTheme(createTheme(plugin.structureRepresentation.themeCtx, { structure: a.data }, params))
  162. // TODO set initial state, repr.setState({})
  163. await repr.createOrUpdate(props, a.data).runInContext(ctx);
  164. return new SO.Molecule.Structure.Representation3D({ repr, source: a } , { label: provider.label });
  165. });
  166. },
  167. update({ a, b, oldParams, newParams }, plugin: PluginContext) {
  168. return Task.create('Structure Representation', async ctx => {
  169. if (newParams.type.name !== oldParams.type.name) return StateTransformer.UpdateResult.Recreate;
  170. const props = { ...b.data.repr.props, ...newParams.type.params }
  171. b.data.repr.setTheme(createTheme(plugin.structureRepresentation.themeCtx, { structure: a.data }, newParams));
  172. await b.data.repr.createOrUpdate(props, a.data).runInContext(ctx);
  173. return StateTransformer.UpdateResult.Updated;
  174. });
  175. }
  176. });
  177. type StructureLabels3D = typeof StructureLabels3D
  178. const StructureLabels3D = PluginStateTransform.BuiltIn({
  179. name: 'structure-labels-3d',
  180. display: '3D Labels',
  181. from: SO.Molecule.Structure,
  182. to: SO.Molecule.Structure.Representation3D,
  183. params: {
  184. // TODO: other targets
  185. target: PD.MappedStatic('residues', {
  186. 'elements': PD.Group({ }),
  187. 'residues': PD.Group({ }),
  188. 'static-text': PD.Group({
  189. value: PD.Text(''),
  190. size: PD.Optional(PD.Numeric(1, { min: 1, max: 1000, step: 0.1 })),
  191. // TODO: this changes the position while rotated etc... fix
  192. position: PD.Optional(Text.Params.attachment)
  193. }, { isFlat: true })
  194. }),
  195. options: PD.Group({
  196. ...Text.Params,
  197. background: PD.Boolean(true),
  198. backgroundMargin: PD.Numeric(0.2, { min: 0, max: 1, step: 0.01 }),
  199. backgroundColor: PD.Color(ColorNames.snow),
  200. backgroundOpacity: PD.Numeric(0.9, { min: 0, max: 1, step: 0.01 }),
  201. })
  202. }
  203. })({
  204. canAutoUpdate({ oldParams, newParams }) {
  205. return (oldParams.target.name === 'static-text' && newParams.target.name === 'static-text' && oldParams.target.params.value === newParams.target.params.value)
  206. || newParams.target.name === oldParams.target.name;
  207. },
  208. apply({ a, params }) {
  209. return Task.create('Structure Labels', async ctx => {
  210. const repr = await getLabelRepresentation(ctx, a.data, params);
  211. return new SO.Molecule.Structure.Representation3D({ repr, source: a }, { label: `Labels`, description: params.target.name });
  212. });
  213. },
  214. update({ a, b, newParams }) {
  215. return Task.create('Structure Labels', async ctx => {
  216. await getLabelRepresentation(ctx, a.data, newParams, b.data.repr as ShapeRepresentation<any, any, any>);
  217. return StateTransformer.UpdateResult.Updated;
  218. });
  219. }
  220. });
  221. type UnwindStructureAssemblyRepresentation3D = typeof UnwindStructureAssemblyRepresentation3D
  222. const UnwindStructureAssemblyRepresentation3D = PluginStateTransform.BuiltIn({
  223. name: 'unwind-structure-assembly-representation-3d',
  224. display: 'Unwind Assembly 3D Representation',
  225. from: SO.Molecule.Structure.Representation3D,
  226. to: SO.Molecule.Structure.Representation3DState,
  227. params: { t: PD.Numeric(0, { min: 0, max: 1, step: 0.01 }) }
  228. })({
  229. canAutoUpdate() {
  230. return true;
  231. },
  232. apply({ a, params }) {
  233. const structure = a.data.source.data;
  234. const unitTransforms = new StructureUnitTransforms(structure);
  235. unwindStructureAssembly(structure, unitTransforms, params.t);
  236. return new SO.Molecule.Structure.Representation3DState({
  237. state: { unitTransforms },
  238. initialState: { unitTransforms: new StructureUnitTransforms(structure) },
  239. info: structure,
  240. source: a
  241. }, { label: `Unwind T = ${params.t.toFixed(2)}` });
  242. },
  243. update({ a, b, newParams, oldParams }) {
  244. const structure = b.data.info as Structure;
  245. if (a.data.source.data !== structure) return StateTransformer.UpdateResult.Recreate;
  246. if (oldParams.t === newParams.t) return StateTransformer.UpdateResult.Unchanged;
  247. const unitTransforms = b.data.state.unitTransforms!;
  248. unwindStructureAssembly(structure, unitTransforms, newParams.t);
  249. b.label = `Unwind T = ${newParams.t.toFixed(2)}`;
  250. b.data.source = a;
  251. return StateTransformer.UpdateResult.Updated;
  252. }
  253. });
  254. type ExplodeStructureRepresentation3D = typeof ExplodeStructureRepresentation3D
  255. const ExplodeStructureRepresentation3D = PluginStateTransform.BuiltIn({
  256. name: 'explode-structure-representation-3d',
  257. display: 'Explode 3D Representation',
  258. from: SO.Molecule.Structure.Representation3D,
  259. to: SO.Molecule.Structure.Representation3DState,
  260. params: { t: PD.Numeric(0, { min: 0, max: 1, step: 0.01 }) }
  261. })({
  262. canAutoUpdate() {
  263. return true;
  264. },
  265. apply({ a, params, spine }) {
  266. const rootStructure = spine.getRootOfType(SO.Molecule.Structure)!.data;
  267. const structure = a.data.source.data;
  268. const unitTransforms = new StructureUnitTransforms(rootStructure);
  269. explodeStructure(structure, unitTransforms, params.t);
  270. return new SO.Molecule.Structure.Representation3DState({
  271. state: { unitTransforms },
  272. initialState: { unitTransforms: new StructureUnitTransforms(rootStructure) },
  273. info: rootStructure,
  274. source: a
  275. }, { label: `Explode T = ${params.t.toFixed(2)}` });
  276. },
  277. update({ a, b, newParams, oldParams, spine }) {
  278. const rootStructure = spine.getRootOfType(SO.Molecule.Structure)!.data;
  279. if (b.data.info !== rootStructure) return StateTransformer.UpdateResult.Recreate;
  280. if (oldParams.t === newParams.t) return StateTransformer.UpdateResult.Unchanged;
  281. const unitTransforms = b.data.state.unitTransforms!;
  282. explodeStructure(rootStructure, unitTransforms, newParams.t);
  283. b.label = `Explode T = ${newParams.t.toFixed(2)}`;
  284. b.data.source = a;
  285. return StateTransformer.UpdateResult.Updated;
  286. }
  287. });
  288. type OverpaintStructureRepresentation3D = typeof OverpaintStructureRepresentation3D
  289. const OverpaintStructureRepresentation3D = PluginStateTransform.BuiltIn({
  290. name: 'overpaint-structure-representation-3d',
  291. display: 'Overpaint 3D Representation',
  292. from: SO.Molecule.Structure.Representation3D,
  293. to: SO.Molecule.Structure.Representation3DState,
  294. params: {
  295. layers: PD.ObjectList({
  296. script: PD.ScriptExpression({ language: 'mol-script', expression: '(sel.atom.atom-groups :residue-test (= atom.resname LYS))' }),
  297. color: PD.Color(ColorNames.blueviolet)
  298. }, e => `${Color.toRgbString(e.color)}`, {
  299. defaultValue: [
  300. {
  301. script: {
  302. language: 'mol-script',
  303. expression: '(sel.atom.atom-groups :residue-test (= atom.resname LYS))'
  304. },
  305. color: ColorNames.blueviolet
  306. },
  307. {
  308. script: {
  309. language: 'mol-script',
  310. expression: '(sel.atom.atom-groups :residue-test (= atom.resname ALA))'
  311. },
  312. color: ColorNames.chartreuse
  313. }
  314. ]
  315. }),
  316. alpha: PD.Numeric(1, { min: 0, max: 1, step: 0.01 }, { label: 'Opacity' }),
  317. }
  318. })({
  319. canAutoUpdate() {
  320. return true;
  321. },
  322. apply({ a, params }) {
  323. const structure = a.data.source.data
  324. const overpaint = getStructureOverpaint(structure, params.layers, params.alpha)
  325. return new SO.Molecule.Structure.Representation3DState({
  326. state: { overpaint },
  327. initialState: { overpaint: Overpaint.Empty },
  328. info: structure,
  329. source: a
  330. }, { label: `Overpaint (${overpaint.layers.length} Layers)` })
  331. },
  332. update({ a, b, newParams, oldParams }) {
  333. const structure = b.data.info as Structure
  334. if (a.data.source.data !== structure) return StateTransformer.UpdateResult.Recreate
  335. const oldOverpaint = b.data.state.overpaint!
  336. const newOverpaint = getStructureOverpaint(structure, newParams.layers, newParams.alpha)
  337. if (oldParams.alpha === newParams.alpha && Overpaint.areEqual(oldOverpaint, newOverpaint)) return StateTransformer.UpdateResult.Unchanged
  338. b.data.state.overpaint = newOverpaint
  339. b.data.source = a
  340. b.label = `Overpaint (${newOverpaint.layers.length} Layers)`
  341. return StateTransformer.UpdateResult.Updated
  342. }
  343. });
  344. //
  345. export namespace VolumeRepresentation3DHelpers {
  346. export function getDefaultParams(ctx: PluginContext, name: BuiltInVolumeRepresentationsName, volume: VolumeData, volumeParams?: Partial<PD.Values<VolumeParams>>): StateTransformer.Params<VolumeRepresentation3D> {
  347. const type = ctx.volumeRepresentation.registry.get(name);
  348. const themeDataCtx = { volume };
  349. const colorParams = ctx.volumeRepresentation.themeCtx.colorThemeRegistry.get(type.defaultColorTheme).getParams(themeDataCtx);
  350. const sizeParams = ctx.volumeRepresentation.themeCtx.sizeThemeRegistry.get(type.defaultSizeTheme).getParams(themeDataCtx)
  351. const volumeDefaultParams = PD.getDefaultValues(type.getParams(ctx.volumeRepresentation.themeCtx, volume))
  352. return ({
  353. type: { name, params: volumeParams ? { ...volumeDefaultParams, ...volumeParams } : volumeDefaultParams },
  354. colorTheme: { name: type.defaultColorTheme, params: PD.getDefaultValues(colorParams) },
  355. sizeTheme: { name: type.defaultSizeTheme, params: PD.getDefaultValues(sizeParams) }
  356. })
  357. }
  358. export function getDefaultParamsStatic(ctx: PluginContext, name: BuiltInVolumeRepresentationsName, volumeParams?: Partial<PD.Values<PD.Params>>, colorName?: BuiltInColorThemeName, colorParams?: Partial<ColorTheme.Props>, sizeName?: BuiltInSizeThemeName, sizeParams?: Partial<SizeTheme.Props>): StateTransformer.Params<VolumeRepresentation3D> {
  359. const type = ctx.volumeRepresentation.registry.get(name);
  360. const colorType = ctx.volumeRepresentation.themeCtx.colorThemeRegistry.get(colorName || type.defaultColorTheme);
  361. const sizeType = ctx.volumeRepresentation.themeCtx.sizeThemeRegistry.get(sizeName || type.defaultSizeTheme);
  362. return ({
  363. type: { name, params: volumeParams ? { ...type.defaultValues, ...volumeParams } : type.defaultValues },
  364. colorTheme: { name: type.defaultColorTheme, params: colorParams ? { ...colorType.defaultValues, ...colorParams } : colorType.defaultValues },
  365. sizeTheme: { name: type.defaultSizeTheme, params: sizeParams ? { ...sizeType.defaultValues, ...sizeParams } : sizeType.defaultValues }
  366. })
  367. }
  368. export function getDescription(props: any) {
  369. return props.isoValue && VolumeIsoValue.toString(props.isoValue)
  370. }
  371. }
  372. type VolumeRepresentation3D = typeof VolumeRepresentation3D
  373. const VolumeRepresentation3D = PluginStateTransform.BuiltIn({
  374. name: 'volume-representation-3d',
  375. display: '3D Representation',
  376. from: SO.Volume.Data,
  377. to: SO.Volume.Representation3D,
  378. params: (a, ctx: PluginContext) => {
  379. const { registry, themeCtx } = ctx.volumeRepresentation
  380. const type = registry.get(registry.default.name);
  381. if (!a) {
  382. return {
  383. type: PD.Mapped<any>(
  384. registry.default.name,
  385. registry.types,
  386. name => PD.Group<any>(registry.get(name).getParams(themeCtx, VolumeData.One ))),
  387. colorTheme: PD.Mapped<any>(
  388. type.defaultColorTheme,
  389. themeCtx.colorThemeRegistry.types,
  390. name => PD.Group<any>(themeCtx.colorThemeRegistry.get(name).getParams({ volume: VolumeData.One }))
  391. ),
  392. sizeTheme: PD.Mapped<any>(
  393. type.defaultSizeTheme,
  394. themeCtx.sizeThemeRegistry.types,
  395. name => PD.Group<any>(themeCtx.sizeThemeRegistry.get(name).getParams({ volume: VolumeData.One }))
  396. )
  397. }
  398. }
  399. const dataCtx = { volume: a.data }
  400. return ({
  401. type: PD.Mapped<any>(
  402. registry.default.name,
  403. registry.types,
  404. name => PD.Group<any>(registry.get(name).getParams(themeCtx, a.data))),
  405. colorTheme: PD.Mapped<any>(
  406. type.defaultColorTheme,
  407. themeCtx.colorThemeRegistry.getApplicableTypes(dataCtx),
  408. name => PD.Group<any>(themeCtx.colorThemeRegistry.get(name).getParams(dataCtx))
  409. ),
  410. sizeTheme: PD.Mapped<any>(
  411. type.defaultSizeTheme,
  412. themeCtx.sizeThemeRegistry.types,
  413. name => PD.Group<any>(themeCtx.sizeThemeRegistry.get(name).getParams(dataCtx))
  414. )
  415. })
  416. }
  417. })({
  418. canAutoUpdate({ oldParams, newParams }) {
  419. // TODO: allow for small molecules
  420. return oldParams.type.name === newParams.type.name;
  421. },
  422. apply({ a, params }, plugin: PluginContext) {
  423. return Task.create('Volume Representation', async ctx => {
  424. const provider = plugin.volumeRepresentation.registry.get(params.type.name)
  425. const props = params.type.params || {}
  426. const repr = provider.factory({ webgl: plugin.canvas3d.webgl, ...plugin.volumeRepresentation.themeCtx }, provider.getParams)
  427. repr.setTheme(createTheme(plugin.volumeRepresentation.themeCtx, { volume: a.data }, params))
  428. // TODO set initial state, repr.setState({})
  429. await repr.createOrUpdate(props, a.data).runInContext(ctx);
  430. return new SO.Volume.Representation3D({ repr, source: a }, { label: provider.label, description: VolumeRepresentation3DHelpers.getDescription(props) });
  431. });
  432. },
  433. update({ a, b, oldParams, newParams }, plugin: PluginContext) {
  434. return Task.create('Volume Representation', async ctx => {
  435. if (newParams.type.name !== oldParams.type.name) return StateTransformer.UpdateResult.Recreate;
  436. const props = { ...b.data.repr.props, ...newParams.type.params }
  437. b.data.repr.setTheme(createTheme(plugin.volumeRepresentation.themeCtx, { volume: a.data }, newParams))
  438. await b.data.repr.createOrUpdate(props, a.data).runInContext(ctx);
  439. b.description = VolumeRepresentation3DHelpers.getDescription(props)
  440. return StateTransformer.UpdateResult.Updated;
  441. });
  442. }
  443. });
  444. export { ShapeRepresentation3D }
  445. type ShapeRepresentation3D = typeof ShapeRepresentation3D
  446. const ShapeRepresentation3D = PluginStateTransform.BuiltIn({
  447. name: 'shape-representation-3d',
  448. display: '3D Representation',
  449. from: SO.Shape.Provider,
  450. to: SO.Shape.Representation3D,
  451. params: (a, ctx: PluginContext) => {
  452. return BaseGeometry.Params
  453. }
  454. })({
  455. canAutoUpdate() {
  456. return true;
  457. },
  458. apply({ a, params }, plugin: PluginContext) {
  459. return Task.create('Shape Representation', async ctx => {
  460. const props = { ...PD.getDefaultValues(a.data.geometryUtils.Params), params }
  461. const repr = ShapeRepresentation(a.data.getShape, a.data.geometryUtils)
  462. // TODO set initial state, repr.setState({})
  463. await repr.createOrUpdate(props, a.data.data).runInContext(ctx);
  464. return new SO.Shape.Representation3D({ repr, source: a }, { label: a.data.label });
  465. });
  466. },
  467. update({ a, b, oldParams, newParams }, plugin: PluginContext) {
  468. return Task.create('Shape Representation', async ctx => {
  469. const props = { ...b.data.repr.props, ...newParams }
  470. await b.data.repr.createOrUpdate(props, a.data.data).runInContext(ctx);
  471. return StateTransformer.UpdateResult.Updated;
  472. });
  473. }
  474. });