representation.ts 28 KB

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