From 67eb9573954c0eec84c21f817e85af07c04d3256 Mon Sep 17 00:00:00 2001 From: Alexander Rose <alex.rose@rcsb.org> Date: Mon, 28 Jan 2019 15:25:56 -0800 Subject: [PATCH] added size support to shape --- src/mol-model/shape/shape.ts | 7 +++-- src/mol-repr/shape/representation.ts | 34 ++++++++++++++++++---- src/mol-theme/size.ts | 2 ++ src/mol-theme/size/shape-group.ts | 43 ++++++++++++++++++++++++++++ src/tests/browser/render-shape.ts | 5 ++-- 5 files changed, 82 insertions(+), 9 deletions(-) create mode 100644 src/mol-theme/size/shape-group.ts diff --git a/src/mol-model/shape/shape.ts b/src/mol-model/shape/shape.ts index 4825815ff..314af70fb 100644 --- a/src/mol-model/shape/shape.ts +++ b/src/mol-model/shape/shape.ts @@ -23,12 +23,14 @@ export interface Shape<G extends Geometry = Geometry> { readonly groupCount: number /** Get color for a given group */ getColor(groupId: number, instanceId: number): Color - /** Get color for a given group */ + /** Get size for a given group */ + getSize(groupId: number, instanceId: number): number + /** Get label for a given group */ getLabel(groupId: number, instanceId: number): string } export namespace Shape { - export function create<G extends Geometry>(name: string, geometry: G, getColor: Shape['getColor'], getLabel: Shape['getLabel'], transforms?: Mat4[]): Shape<G> { + export function create<G extends Geometry>(name: string, geometry: G, getColor: Shape['getColor'], getSize: Shape['getSize'], getLabel: Shape['getLabel'], transforms?: Mat4[]): Shape<G> { return { id: UUID.create22(), name, @@ -36,6 +38,7 @@ export namespace Shape { transforms: transforms || [Mat4.identity()], get groupCount() { return Geometry.getGroupCount(geometry) }, getColor, + getSize, getLabel } } diff --git a/src/mol-repr/shape/representation.ts b/src/mol-repr/shape/representation.ts index 275429978..11f405ce4 100644 --- a/src/mol-repr/shape/representation.ts +++ b/src/mol-repr/shape/representation.ts @@ -24,6 +24,8 @@ import { createColors } from 'mol-geo/geometry/color-data'; import { VisualUpdateState } from 'mol-repr/util'; import { Mat4 } from 'mol-math/linear-algebra'; import { Visual } from 'mol-repr/visual'; +import { createSizes } from 'mol-geo/geometry/size-data'; +import { ShapeGroupSizeTheme } from 'mol-theme/size/shape-group'; export interface ShapeRepresentation<D, G extends Geometry, P extends Geometry.Params<G>> extends Representation<D, P> { } @@ -43,7 +45,7 @@ export function ShapeRepresentation<D, G extends Geometry, P extends Geometry.Pa const updateState = VisualUpdateState.create() - function prepareUpdate(shape?: Shape<G>) { + function prepareUpdate(props: Partial<PD.Values<P>> = {}, shape?: Shape<G>) { VisualUpdateState.reset(updateState) if (!shape && !_shape) { @@ -59,9 +61,8 @@ export function ShapeRepresentation<D, G extends Geometry, P extends Geometry.Pa updateState.updateTransform = true } else if (shape && _shape && shape.id !== _shape.id) { console.log('new shape') - // assume that ValueCells in geometry of new shape where re-used from the old one - updateState.updateColor = true updateState.updateTransform = true + updateState.createGeometry = true } else if (!shape) { console.log('only props') // nothing to set @@ -72,6 +73,10 @@ export function ShapeRepresentation<D, G extends Geometry, P extends Geometry.Pa if (updateState.updateTransform) { updateState.updateColor = true } + + if (updateState.createGeometry) { + updateState.updateColor = true + } } function createOrUpdate(props: Partial<PD.Values<P>> = {}, data?: D) { @@ -79,11 +84,12 @@ export function ShapeRepresentation<D, G extends Geometry, P extends Geometry.Pa const newProps = Object.assign(currentProps, props) const shape = data ? await getShape(runtime, data, newProps, _shape) : undefined - prepareUpdate(shape) + prepareUpdate(props, shape) if (shape) { _shape = shape _theme.color = ShapeGroupColorTheme({ shape: _shape }, {}) + _theme.size = ShapeGroupSizeTheme({ shape: _shape }, {}) } if (updateState.createNew) { @@ -108,11 +114,29 @@ export function ShapeRepresentation<D, G extends Geometry, P extends Geometry.Pa createMarkers(instanceCount * groupCount, _renderObject.values) } + if (updateState.createGeometry) { + // console.log('update geometry') + ValueCell.update(_renderObject.values.drawCount, Geometry.getDrawCount(_shape.geometry)) + } + + if (updateState.updateTransform || updateState.createGeometry) { + // console.log('updateBoundingSphere') + geometryUtils.updateBoundingSphere(_renderObject.values, _shape.geometry) + } + if (updateState.updateColor) { // console.log('update color') createColors(locationIt, _theme.color, _renderObject.values) } + if (updateState.updateSize) { + // not all geometries have size data, so check here + if ('uSize' in _renderObject.values) { + console.log('update size') + createSizes(locationIt, _theme.size, _renderObject.values) + } + } + geometryUtils.updateValues(_renderObject.values, newProps) geometryUtils.updateRenderableState(_renderObject.state, newProps) } @@ -176,7 +200,7 @@ export function ShapeRepresentation<D, G extends Geometry, P extends Geometry.Pa Representation.updateState(_state, state) }, setTheme(theme: Theme) { - console.warn('The `ShapeRepresentation` theme is fixed to `ShapeGroupColorTheme`. Colors are taken from `Shape.getColor`.') + console.warn('The `ShapeRepresentation` theme is fixed to `ShapeGroupColorTheme` and `ShapeGroupSizeTheme`. Colors are taken from `Shape.getColor` and sizes from `Shape.getSize`') }, destroy() { // TODO diff --git a/src/mol-theme/size.ts b/src/mol-theme/size.ts index 11dd21588..52469b7a1 100644 --- a/src/mol-theme/size.ts +++ b/src/mol-theme/size.ts @@ -10,6 +10,7 @@ import { ParamDefinition as PD } from 'mol-util/param-definition'; import { ThemeDataContext, ThemeRegistry, ThemeProvider } from 'mol-theme/theme'; import { PhysicalSizeThemeProvider } from './size/physical'; import { deepEqual } from 'mol-util'; +import { ShapeGroupSizeThemeProvider } from './size/shape-group'; export { SizeTheme } interface SizeTheme<P extends PD.Params> { @@ -40,5 +41,6 @@ namespace SizeTheme { export const BuiltInSizeThemes = { 'physical': PhysicalSizeThemeProvider, + 'shape-group': ShapeGroupSizeThemeProvider, 'uniform': UniformSizeThemeProvider } \ No newline at end of file diff --git a/src/mol-theme/size/shape-group.ts b/src/mol-theme/size/shape-group.ts new file mode 100644 index 000000000..60fa329f3 --- /dev/null +++ b/src/mol-theme/size/shape-group.ts @@ -0,0 +1,43 @@ +/** + * Copyright (c) 2019 mol* contributors, licensed under MIT, See LICENSE file for more info. + * + * @author Alexander Rose <alexander.rose@weirdbyte.de> + */ + +import { Location } from 'mol-model/location'; +import { Shape } from 'mol-model/shape'; +import { ParamDefinition as PD } from 'mol-util/param-definition' +import { ThemeDataContext } from 'mol-theme/theme'; +import { SizeTheme } from 'mol-theme/size'; + +const DefaultSize = 1 +const Description = 'Assigns sizes as defined by the shape object.' + +export const ShapeGroupSizeThemeParams = {} +export type ShapeGroupSizeThemeParams = typeof ShapeGroupSizeThemeParams +export function getShapeGroupSizeThemeParams(ctx: ThemeDataContext) { + return ShapeGroupSizeThemeParams // TODO return copy +} + +export function ShapeGroupSizeTheme(ctx: ThemeDataContext, props: PD.Values<ShapeGroupSizeThemeParams>): SizeTheme<ShapeGroupSizeThemeParams> { + return { + factory: ShapeGroupSizeTheme, + granularity: 'groupInstance', + size: (location: Location): number => { + if (Shape.isLocation(location)) { + return location.shape.getSize(location.group, location.instance) + } + return DefaultSize + }, + props, + description: Description + } +} + +export const ShapeGroupSizeThemeProvider: SizeTheme.Provider<ShapeGroupSizeThemeParams> = { + label: 'Shape Group', + factory: ShapeGroupSizeTheme, + getParams: getShapeGroupSizeThemeParams, + defaultValues: PD.getDefaultValues(ShapeGroupSizeThemeParams), + isApplicable: (ctx: ThemeDataContext) => !!ctx.shape +} \ No newline at end of file diff --git a/src/tests/browser/render-shape.ts b/src/tests/browser/render-shape.ts index a688de0dc..943a50476 100644 --- a/src/tests/browser/render-shape.ts +++ b/src/tests/browser/render-shape.ts @@ -86,8 +86,9 @@ async function getShape(ctx: RuntimeContext, data: MyData, props: {}, shape?: Sh const groupCount = centers.length / 3 return shape || Shape.create( 'test', mesh, - (groupId: number) => colors[groupId], // per group, same for instances - (groupId: number, instanceId: number) => labels[instanceId * groupCount + groupId], // per group and instance + (groupId: number) => colors[groupId], // color: per group, same for instances + () => 1, // size: constant + (groupId: number, instanceId: number) => labels[instanceId * groupCount + groupId], // label: per group and instance transforms ) } -- GitLab