From 8d4e760856c6df2ada985a27f155f984892f20f3 Mon Sep 17 00:00:00 2001 From: Alexander Rose <alex.rose@rcsb.org> Date: Fri, 10 Aug 2018 17:46:58 -0700 Subject: [PATCH] wip, refactoring of representations and visuals --- src/mol-app/ui/transform/file-loader.tsx | 8 +- src/mol-app/ui/transform/url-loader.tsx | 10 +- src/mol-geo/representation/index.ts | 8 +- .../structure/complex-representation.ts | 6 +- .../structure/complex-visual.ts | 79 +++++++++++++- src/mol-geo/representation/structure/index.ts | 10 +- .../structure/representation/backbone.ts | 15 +-- .../representation/ball-and-stick.ts | 23 ++-- .../structure/representation/carbohydrate.ts | 19 ++-- .../structure/representation/cartoon.ts | 27 ++--- .../representation/distance-restraint.ts | 16 +-- .../structure/representation/spacefill.ts | 4 +- .../structure/units-representation.ts | 6 +- .../representation/structure/units-visual.ts | 95 +++++++++++++++- .../visual/carbohydrate-link-cylinder.ts | 62 ++--------- .../visual/carbohydrate-symbol-mesh.ts | 64 ++--------- .../visual/cross-link-restraint-cylinder.ts | 92 +++++----------- .../structure/visual/element-point.ts | 4 +- .../structure/visual/element-sphere.ts | 97 +++-------------- .../visual/inter-unit-link-cylinder.ts | 64 ++--------- .../visual/intra-unit-link-cylinder.ts | 71 ++---------- .../structure/visual/nucleotide-block-mesh.ts | 92 +++------------- .../visual/polymer-backbone-cylinder.ts | 92 +++------------- .../visual/polymer-direction-wedge.ts | 103 +++--------------- .../structure/visual/polymer-gap-cylinder.ts | 92 +++------------- .../structure/visual/polymer-trace-mesh.ts | 103 +++--------------- .../structure/visual/util/common.ts | 11 +- .../structure/visual/util/element.ts | 22 +++- src/mol-geo/representation/util.ts | 4 +- src/mol-geo/representation/volume/index.ts | 14 ++- .../structure/unit/pair-restraints/data.ts | 11 +- .../pair-restraints/extract-cross-links.ts | 13 ++- src/mol-view/stage.ts | 12 +- src/mol-view/state/entity.ts | 12 +- src/mol-view/state/transform.ts | 60 +++++----- 35 files changed, 495 insertions(+), 926 deletions(-) diff --git a/src/mol-app/ui/transform/file-loader.tsx b/src/mol-app/ui/transform/file-loader.tsx index 02f76c55c..32712dfa0 100644 --- a/src/mol-app/ui/transform/file-loader.tsx +++ b/src/mol-app/ui/transform/file-loader.tsx @@ -16,14 +16,14 @@ import { BallAndStickProps } from 'mol-geo/representation/structure/representati import { DistanceRestraintProps } from 'mol-geo/representation/structure/representation/distance-restraint'; import { BackboneProps } from 'mol-geo/representation/structure/representation/backbone'; -const spacefillProps: SpacefillProps = { +const spacefillProps: Partial<SpacefillProps> = { doubleSided: true, colorTheme: { name: 'chain-id' }, quality: 'auto', useFog: false } -const ballAndStickProps: BallAndStickProps = { +const ballAndStickProps: Partial<BallAndStickProps> = { doubleSided: true, colorTheme: { name: 'chain-id' }, sizeTheme: { name: 'uniform', value: 0.05 }, @@ -32,7 +32,7 @@ const ballAndStickProps: BallAndStickProps = { useFog: false } -const distanceRestraintProps: DistanceRestraintProps = { +const distanceRestraintProps: Partial<DistanceRestraintProps> = { doubleSided: true, colorTheme: { name: 'chain-id' }, linkRadius: 0.5, @@ -40,7 +40,7 @@ const distanceRestraintProps: DistanceRestraintProps = { useFog: false } -const backboneProps: BackboneProps = { +const backboneProps: Partial<BackboneProps> = { doubleSided: true, colorTheme: { name: 'chain-id' }, quality: 'auto', diff --git a/src/mol-app/ui/transform/url-loader.tsx b/src/mol-app/ui/transform/url-loader.tsx index ed0b8ef8b..58667e93d 100644 --- a/src/mol-app/ui/transform/url-loader.tsx +++ b/src/mol-app/ui/transform/url-loader.tsx @@ -16,14 +16,14 @@ import { DistanceRestraintProps } from 'mol-geo/representation/structure/represe import { BackboneProps } from 'mol-geo/representation/structure/representation/backbone'; import { CartoonProps } from 'mol-geo/representation/structure/representation/cartoon'; -const spacefillProps: SpacefillProps = { +const spacefillProps: Partial<SpacefillProps> = { doubleSided: true, colorTheme: { name: 'chain-id' }, quality: 'auto', useFog: false } -const ballAndStickProps: BallAndStickProps = { +const ballAndStickProps: Partial<BallAndStickProps> = { doubleSided: true, colorTheme: { name: 'chain-id' }, sizeTheme: { name: 'uniform', value: 0.05 }, @@ -32,7 +32,7 @@ const ballAndStickProps: BallAndStickProps = { useFog: false } -const distanceRestraintProps: DistanceRestraintProps = { +const distanceRestraintProps: Partial<DistanceRestraintProps> = { doubleSided: true, colorTheme: { name: 'chain-id' }, linkRadius: 0.5, @@ -40,14 +40,14 @@ const distanceRestraintProps: DistanceRestraintProps = { useFog: false } -const backboneProps: BackboneProps = { +const backboneProps: Partial<BackboneProps> = { doubleSided: true, colorTheme: { name: 'chain-id' }, quality: 'auto', useFog: false } -const cartoonProps: CartoonProps = { +const cartoonProps: Partial<CartoonProps> = { doubleSided: true, colorTheme: { name: 'chain-id' }, quality: 'auto', diff --git a/src/mol-geo/representation/index.ts b/src/mol-geo/representation/index.ts index ab18c4cdf..a444545fe 100644 --- a/src/mol-geo/representation/index.ts +++ b/src/mol-geo/representation/index.ts @@ -15,8 +15,8 @@ export interface RepresentationProps {} export interface Representation<D, P extends RepresentationProps = {}> { readonly renderObjects: ReadonlyArray<RenderObject> readonly props: Readonly<P> - create: (data: D, props?: P) => Task<void> - update: (props: P) => Task<void> + create: (data: D, props?: Partial<P>) => Task<void> + update: (props: Partial<P>) => Task<void> getLoci: (pickingId: PickingId) => Loci mark: (loci: Loci, action: MarkerAction) => void destroy: () => void @@ -24,8 +24,8 @@ export interface Representation<D, P extends RepresentationProps = {}> { export interface Visual<D, P extends RepresentationProps = {}> { readonly renderObject: RenderObject - create: (ctx: RuntimeContext, data: D, props: P) => Promise<void> - update: (ctx: RuntimeContext, props: P) => Promise<boolean> + create: (ctx: RuntimeContext, data: D, props?: Partial<P>) => Promise<void> + update: (ctx: RuntimeContext, props: Partial<P>) => Promise<boolean> getLoci: (pickingId: PickingId) => Loci mark: (loci: Loci, action: MarkerAction) => void destroy: () => void diff --git a/src/mol-geo/representation/structure/complex-representation.ts b/src/mol-geo/representation/structure/complex-representation.ts index 2ddb9d8cb..5bc2b81a2 100644 --- a/src/mol-geo/representation/structure/complex-representation.ts +++ b/src/mol-geo/representation/structure/complex-representation.ts @@ -17,10 +17,10 @@ import { ComplexVisual } from './complex-visual'; export function ComplexRepresentation<P extends StructureProps>(visualCtor: () => ComplexVisual<P>): StructureRepresentation<P> { let visual: ComplexVisual<P> - let _props: Required<P> + let _props: P let _structure: Structure - function create(structure: Structure, props: P = {} as P) { + function create(structure: Structure, props: Partial<P> = {}) { _props = Object.assign({}, DefaultStructureProps, _props, props, getQualityProps(props, structure)) _props.colorTheme!.structure = structure @@ -41,7 +41,7 @@ export function ComplexRepresentation<P extends StructureProps>(visualCtor: () = }); } - function update(props: P) { + function update(props: Partial<P>) { return Task.create('Updating StructureRepresentation', async ctx => { _props = Object.assign({}, DefaultStructureProps, _props, props, getQualityProps(props, _structure)) _props.colorTheme!.structure = _structure diff --git a/src/mol-geo/representation/structure/complex-visual.ts b/src/mol-geo/representation/structure/complex-visual.ts index 8c193d515..9c02d9861 100644 --- a/src/mol-geo/representation/structure/complex-visual.ts +++ b/src/mol-geo/representation/structure/complex-visual.ts @@ -2,10 +2,83 @@ * Copyright (c) 2018 mol* contributors, licensed under MIT, See LICENSE file for more info. * * @author Alexander Rose <alexander.rose@weirdbyte.de> - * @author David Sehnal <david.sehnal@gmail.com> */ import { Structure } from 'mol-model/structure'; -import { RepresentationProps, Visual } from '..'; +import { Visual } from '..'; +import { MeshRenderObject } from 'mol-gl/render-object'; +import { Mesh } from '../../shape/mesh'; +import { RuntimeContext } from 'mol-task'; +import { LocationIterator } from './visual/util/location-iterator'; +import { createComplexMeshRenderObject, createColors } from './visual/util/common'; +import { StructureMeshProps, StructureProps } from '.'; +import { deepEqual } from 'mol-util'; +import { updateMeshValues, updateRenderableState } from '../util'; +import { PickingId } from '../../util/picking'; +import { Loci } from 'mol-model/loci'; +import { MarkerAction, MarkerData } from '../../util/marker-data'; -export interface ComplexVisual<P extends RepresentationProps = {}> extends Visual<Structure, P> { } \ No newline at end of file +export interface ComplexVisual<P extends StructureProps> extends Visual<Structure, P> { } + +export interface ComplexMeshVisualBuilder<P extends StructureMeshProps> { + defaultProps: P + createMesh(ctx: RuntimeContext, structure: Structure, props: P, mesh?: Mesh): Promise<Mesh> + createLocationIterator(structure: Structure): LocationIterator + getLoci(pickingId: PickingId, structure: Structure, id: number): Loci + mark(loci: Loci, action: MarkerAction, structure: Structure, values: MarkerData): void +} + +export function ComplexMeshVisual<P extends StructureMeshProps>(builder: ComplexMeshVisualBuilder<P>): ComplexVisual<P> { + const { defaultProps, createMesh, createLocationIterator, getLoci, mark } = builder + + let renderObject: MeshRenderObject + let currentProps: P + let mesh: Mesh + let currentStructure: Structure + + return { + get renderObject () { return renderObject }, + async create(ctx: RuntimeContext, structure: Structure, props: Partial<P> = {}) { + currentProps = Object.assign({}, defaultProps, props) + currentStructure = structure + + mesh = await createMesh(ctx, currentStructure, currentProps, mesh) + + const locationIt = createLocationIterator(structure) + renderObject = createComplexMeshRenderObject(structure, mesh, locationIt, currentProps) + }, + async update(ctx: RuntimeContext, props: Partial<P>) { + const newProps = Object.assign({}, currentProps, props) + + if (!renderObject) return false + + let updateColor = false + + // TODO create in-place + // if (currentProps.radialSegments !== newProps.radialSegments) return false + + if (!deepEqual(newProps.colorTheme, currentProps.colorTheme)) { + updateColor = true + } + + if (updateColor) { + createColors(createLocationIterator(currentStructure), newProps.colorTheme, renderObject.values) + } + + updateMeshValues(renderObject.values, newProps) + updateRenderableState(renderObject.state, newProps) + + currentProps = newProps + return false + }, + getLoci(pickingId: PickingId) { + return getLoci(pickingId, currentStructure, renderObject.id) + }, + mark(loci: Loci, action: MarkerAction) { + mark(loci, action, currentStructure, renderObject.values) + }, + destroy() { + // TODO + } + } +} \ No newline at end of file diff --git a/src/mol-geo/representation/structure/index.ts b/src/mol-geo/representation/structure/index.ts index 2b0b0da9c..951d43369 100644 --- a/src/mol-geo/representation/structure/index.ts +++ b/src/mol-geo/representation/structure/index.ts @@ -8,7 +8,7 @@ import { Structure } from 'mol-model/structure'; import { Representation, RepresentationProps } from '..'; import { ColorTheme, SizeTheme } from '../../theme'; -import { DefaultBaseProps } from '../util'; +import { DefaultBaseProps, DefaultMeshProps } from '../util'; export interface StructureRepresentation<P extends RepresentationProps = {}> extends Representation<Structure, P> { } @@ -17,7 +17,13 @@ export const DefaultStructureProps = { colorTheme: { name: 'instance-index' } as ColorTheme, sizeTheme: { name: 'physical' } as SizeTheme, } -export type StructureProps = Partial<typeof DefaultStructureProps> +export type StructureProps = typeof DefaultStructureProps + +export const DefaultStructureMeshProps = { + ...DefaultStructureProps, + ...DefaultMeshProps +} +export type StructureMeshProps = typeof DefaultStructureMeshProps export { ComplexRepresentation } from './complex-representation' export { UnitsRepresentation } from './units-representation' diff --git a/src/mol-geo/representation/structure/representation/backbone.ts b/src/mol-geo/representation/structure/representation/backbone.ts index 4930d9775..2afb0c8cf 100644 --- a/src/mol-geo/representation/structure/representation/backbone.ts +++ b/src/mol-geo/representation/structure/representation/backbone.ts @@ -15,11 +15,12 @@ import { PolymerBackboneVisual, DefaultPolymerBackboneProps } from '../visual/po export const DefaultBackboneProps = { ...DefaultPolymerBackboneProps } -export type BackboneProps = Partial<typeof DefaultBackboneProps> +export type BackboneProps = typeof DefaultBackboneProps export function BackboneRepresentation(): StructureRepresentation<BackboneProps> { const traceRepr = UnitsRepresentation(PolymerBackboneVisual) + let currentProps: BackboneProps return { get renderObjects() { return [ ...traceRepr.renderObjects ] @@ -27,16 +28,16 @@ export function BackboneRepresentation(): StructureRepresentation<BackboneProps> get props() { return { ...traceRepr.props } }, - create: (structure: Structure, props: BackboneProps = {} as BackboneProps) => { - const p = Object.assign({}, DefaultBackboneProps, props) + create: (structure: Structure, props: Partial<BackboneProps> = {}) => { + currentProps = Object.assign({}, DefaultBackboneProps, props) return Task.create('BackboneRepresentation', async ctx => { - await traceRepr.create(structure, p).runInContext(ctx) + await traceRepr.create(structure, currentProps).runInContext(ctx) }) }, - update: (props: BackboneProps) => { - const p = Object.assign({}, props) + update: (props: Partial<BackboneProps>) => { + currentProps = Object.assign(currentProps, props) return Task.create('Updating BackboneRepresentation', async ctx => { - await traceRepr.update(p).runInContext(ctx) + await traceRepr.update(currentProps).runInContext(ctx) }) }, getLoci: (pickingId: PickingId) => { diff --git a/src/mol-geo/representation/structure/representation/ball-and-stick.ts b/src/mol-geo/representation/structure/representation/ball-and-stick.ts index 094eb1fcb..b32faf0ce 100644 --- a/src/mol-geo/representation/structure/representation/ball-and-stick.ts +++ b/src/mol-geo/representation/structure/representation/ball-and-stick.ts @@ -22,13 +22,14 @@ export const DefaultBallAndStickProps = { sizeTheme: { name: 'uniform', value: 0.25 } as SizeTheme, unitKinds: [ Unit.Kind.Atomic ] as Unit.Kind[] } -export type BallAndStickProps = Partial<typeof DefaultBallAndStickProps> +export type BallAndStickProps = typeof DefaultBallAndStickProps export function BallAndStickRepresentation(): StructureRepresentation<BallAndStickProps> { const elmementRepr = UnitsRepresentation(ElementSphereVisual) const intraLinkRepr = UnitsRepresentation(IntraUnitLinkVisual) const interLinkRepr = ComplexRepresentation(InterUnitLinkVisual) + let currentProps: BallAndStickProps return { get renderObjects() { return [ ...elmementRepr.renderObjects, ...intraLinkRepr.renderObjects, ...interLinkRepr.renderObjects ] @@ -36,20 +37,20 @@ export function BallAndStickRepresentation(): StructureRepresentation<BallAndSti get props() { return { ...elmementRepr.props, ...intraLinkRepr.props, ...interLinkRepr.props } }, - create: (structure: Structure, props: BallAndStickProps = {} as BallAndStickProps) => { - const p = Object.assign({}, DefaultBallAndStickProps, props) + create: (structure: Structure, props: Partial<BallAndStickProps> = {}) => { + currentProps = Object.assign({}, DefaultBallAndStickProps, props) return Task.create('DistanceRestraintRepresentation', async ctx => { - await elmementRepr.create(structure, p).runInContext(ctx) - await intraLinkRepr.create(structure, p).runInContext(ctx) - await interLinkRepr.create(structure, p).runInContext(ctx) + await elmementRepr.create(structure, currentProps).runInContext(ctx) + await intraLinkRepr.create(structure, currentProps).runInContext(ctx) + await interLinkRepr.create(structure, currentProps).runInContext(ctx) }) }, - update: (props: BallAndStickProps) => { - const p = Object.assign({}, props) + update: (props: Partial<BallAndStickProps>) => { + currentProps = Object.assign(currentProps, props) return Task.create('Updating BallAndStickRepresentation', async ctx => { - await elmementRepr.update(p).runInContext(ctx) - await intraLinkRepr.update(p).runInContext(ctx) - await interLinkRepr.update(p).runInContext(ctx) + await elmementRepr.update(currentProps).runInContext(ctx) + await intraLinkRepr.update(currentProps).runInContext(ctx) + await interLinkRepr.update(currentProps).runInContext(ctx) }) }, getLoci: (pickingId: PickingId) => { diff --git a/src/mol-geo/representation/structure/representation/carbohydrate.ts b/src/mol-geo/representation/structure/representation/carbohydrate.ts index 75e63d930..bc877da0f 100644 --- a/src/mol-geo/representation/structure/representation/carbohydrate.ts +++ b/src/mol-geo/representation/structure/representation/carbohydrate.ts @@ -17,12 +17,13 @@ export const DefaultCartoonProps = { ...DefaultCarbohydrateSymbolProps, ...DefaultCarbohydrateLinkProps } -export type CarbohydrateProps = Partial<typeof DefaultCartoonProps> +export type CarbohydrateProps = typeof DefaultCartoonProps export function CarbohydrateRepresentation(): StructureRepresentation<CarbohydrateProps> { const carbohydrateSymbolRepr = ComplexRepresentation(CarbohydrateSymbolVisual) const carbohydrateLinkRepr = ComplexRepresentation(CarbohydrateLinkVisual) + let currentProps: CarbohydrateProps return { get renderObjects() { return [ ...carbohydrateSymbolRepr.renderObjects, ...carbohydrateLinkRepr.renderObjects ] @@ -30,18 +31,18 @@ export function CarbohydrateRepresentation(): StructureRepresentation<Carbohydra get props() { return { ...carbohydrateSymbolRepr.props, ...carbohydrateLinkRepr.props } }, - create: (structure: Structure, props: CarbohydrateProps = {} as CarbohydrateProps) => { - const p = Object.assign({}, DefaultCartoonProps, props) + create: (structure: Structure, props: Partial<CarbohydrateProps> = {} as CarbohydrateProps) => { + currentProps = Object.assign({}, DefaultCartoonProps, props) return Task.create('Creating CarbohydrateRepresentation', async ctx => { - await carbohydrateSymbolRepr.create(structure, p).runInContext(ctx) - await carbohydrateLinkRepr.create(structure, p).runInContext(ctx) + await carbohydrateSymbolRepr.create(structure, currentProps).runInContext(ctx) + await carbohydrateLinkRepr.create(structure, currentProps).runInContext(ctx) }) }, - update: (props: CarbohydrateProps) => { - const p = Object.assign({}, props) + update: (props: Partial<CarbohydrateProps>) => { + currentProps = Object.assign(currentProps, props) return Task.create('Updating CarbohydrateRepresentation', async ctx => { - await carbohydrateSymbolRepr.update(p).runInContext(ctx) - await carbohydrateLinkRepr.update(p).runInContext(ctx) + await carbohydrateSymbolRepr.update(currentProps).runInContext(ctx) + await carbohydrateLinkRepr.update(currentProps).runInContext(ctx) }) }, getLoci: (pickingId: PickingId) => { diff --git a/src/mol-geo/representation/structure/representation/cartoon.ts b/src/mol-geo/representation/structure/representation/cartoon.ts index 498c0f30b..904b43360 100644 --- a/src/mol-geo/representation/structure/representation/cartoon.ts +++ b/src/mol-geo/representation/structure/representation/cartoon.ts @@ -21,7 +21,7 @@ export const DefaultCartoonProps = { ...DefaultNucleotideBlockProps, ...DefaultPolymerDirectionProps } -export type CartoonProps = Partial<typeof DefaultCartoonProps> +export type CartoonProps = typeof DefaultCartoonProps export function CartoonRepresentation(): StructureRepresentation<CartoonProps> { const traceRepr = UnitsRepresentation(PolymerTraceVisual) @@ -29,6 +29,7 @@ export function CartoonRepresentation(): StructureRepresentation<CartoonProps> { const blockRepr = UnitsRepresentation(NucleotideBlockVisual) const directionRepr = UnitsRepresentation(PolymerDirectionVisual) + let currentProps: CartoonProps return { get renderObjects() { return [ ...traceRepr.renderObjects, ...gapRepr.renderObjects, @@ -37,22 +38,22 @@ export function CartoonRepresentation(): StructureRepresentation<CartoonProps> { get props() { return { ...traceRepr.props, ...gapRepr.props, ...blockRepr.props } }, - create: (structure: Structure, props: CartoonProps = {} as CartoonProps) => { - const p = Object.assign({}, DefaultCartoonProps, props) + create: (structure: Structure, props: Partial<CartoonProps> = {}) => { + currentProps = Object.assign({}, DefaultCartoonProps, props) return Task.create('Creating CartoonRepresentation', async ctx => { - await traceRepr.create(structure, p).runInContext(ctx) - await gapRepr.create(structure, p).runInContext(ctx) - await blockRepr.create(structure, p).runInContext(ctx) - await directionRepr.create(structure, p).runInContext(ctx) + await traceRepr.create(structure, currentProps).runInContext(ctx) + await gapRepr.create(structure, currentProps).runInContext(ctx) + await blockRepr.create(structure, currentProps).runInContext(ctx) + await directionRepr.create(structure, currentProps).runInContext(ctx) }) }, - update: (props: CartoonProps) => { - const p = Object.assign({}, props) + update: (props: Partial<CartoonProps>) => { + currentProps = Object.assign(currentProps, props) return Task.create('Updating CartoonRepresentation', async ctx => { - await traceRepr.update(p).runInContext(ctx) - await gapRepr.update(p).runInContext(ctx) - await blockRepr.update(p).runInContext(ctx) - await directionRepr.update(p).runInContext(ctx) + await traceRepr.update(currentProps).runInContext(ctx) + await gapRepr.update(currentProps).runInContext(ctx) + await blockRepr.update(currentProps).runInContext(ctx) + await directionRepr.update(currentProps).runInContext(ctx) }) }, getLoci: (pickingId: PickingId) => { diff --git a/src/mol-geo/representation/structure/representation/distance-restraint.ts b/src/mol-geo/representation/structure/representation/distance-restraint.ts index 68d2d994c..6618ce311 100644 --- a/src/mol-geo/representation/structure/representation/distance-restraint.ts +++ b/src/mol-geo/representation/structure/representation/distance-restraint.ts @@ -15,14 +15,14 @@ import { CrossLinkRestraintVisual, DefaultCrossLinkRestraintProps } from '../vis export const DefaultDistanceRestraintProps = { ...DefaultCrossLinkRestraintProps, - sizeTheme: { name: 'uniform', value: 0.25 } as SizeTheme, } -export type DistanceRestraintProps = Partial<typeof DefaultDistanceRestraintProps> +export type DistanceRestraintProps = typeof DefaultDistanceRestraintProps export function DistanceRestraintRepresentation(): StructureRepresentation<DistanceRestraintProps> { const crossLinkRepr = ComplexRepresentation(CrossLinkRestraintVisual) + let currentProps: DistanceRestraintProps return { get renderObjects() { return [ ...crossLinkRepr.renderObjects ] @@ -30,16 +30,16 @@ export function DistanceRestraintRepresentation(): StructureRepresentation<Dista get props() { return { ...crossLinkRepr.props } }, - create: (structure: Structure, props: DistanceRestraintProps = {} as DistanceRestraintProps) => { - const p = Object.assign({}, DefaultDistanceRestraintProps, props) + create: (structure: Structure, props: Partial<DistanceRestraintProps> = {}) => { + currentProps = Object.assign({}, DefaultDistanceRestraintProps, props) return Task.create('DistanceRestraintRepresentation', async ctx => { - await crossLinkRepr.create(structure, p).runInContext(ctx) + await crossLinkRepr.create(structure, currentProps).runInContext(ctx) }) }, - update: (props: DistanceRestraintProps) => { - const p = Object.assign({}, props) + update: (props: Partial<DistanceRestraintProps>) => { + currentProps = Object.assign(currentProps, props) return Task.create('Updating DistanceRestraintRepresentation', async ctx => { - await crossLinkRepr.update(p).runInContext(ctx) + await crossLinkRepr.update(currentProps).runInContext(ctx) }) }, getLoci: (pickingId: PickingId) => { diff --git a/src/mol-geo/representation/structure/representation/spacefill.ts b/src/mol-geo/representation/structure/representation/spacefill.ts index 0fab7f5a9..d2062b297 100644 --- a/src/mol-geo/representation/structure/representation/spacefill.ts +++ b/src/mol-geo/representation/structure/representation/spacefill.ts @@ -8,9 +8,9 @@ import { UnitsRepresentation } from '..'; import { ElementSphereVisual, DefaultElementSphereProps } from '../visual/element-sphere'; export const DefaultSpacefillProps = { - ...DefaultElementSphereProps, + ...DefaultElementSphereProps } -export type SpacefillProps = Partial<typeof DefaultSpacefillProps> +export type SpacefillProps = typeof DefaultSpacefillProps export function SpacefillRepresentation() { return UnitsRepresentation(ElementSphereVisual) diff --git a/src/mol-geo/representation/structure/units-representation.ts b/src/mol-geo/representation/structure/units-representation.ts index eb9a9efdb..78c3a5795 100644 --- a/src/mol-geo/representation/structure/units-representation.ts +++ b/src/mol-geo/representation/structure/units-representation.ts @@ -23,11 +23,11 @@ export interface StructureRepresentation<P extends RepresentationProps = {}> ext export function UnitsRepresentation<P extends StructureProps>(visualCtor: () => UnitsVisual<P>): StructureRepresentation<P> { let visuals = new Map<number, { group: Unit.SymmetryGroup, visual: UnitsVisual<P> }>() - let _props: Required<P> + let _props: P let _structure: Structure let _groups: ReadonlyArray<Unit.SymmetryGroup> - function create(structure: Structure, props: P = {} as P) { + function create(structure: Structure, props: Partial<P> = {}) { _props = Object.assign({}, DefaultStructureProps, _props, props, getQualityProps(props, structure)) _props.colorTheme!.structure = structure @@ -80,7 +80,7 @@ export function UnitsRepresentation<P extends StructureProps>(visualCtor: () => }); } - function update(props: P) { + function update(props: Partial<P>) { return Task.create('Updating StructureRepresentation', async ctx => { _props = Object.assign({}, DefaultStructureProps, _props, props, getQualityProps(props, _structure)) _props.colorTheme!.structure = _structure diff --git a/src/mol-geo/representation/structure/units-visual.ts b/src/mol-geo/representation/structure/units-visual.ts index 540aa7fec..f91783253 100644 --- a/src/mol-geo/representation/structure/units-visual.ts +++ b/src/mol-geo/representation/structure/units-visual.ts @@ -2,10 +2,101 @@ * Copyright (c) 2018 mol* contributors, licensed under MIT, See LICENSE file for more info. * * @author Alexander Rose <alexander.rose@weirdbyte.de> - * @author David Sehnal <david.sehnal@gmail.com> */ -import { RepresentationProps, Visual } from '..'; import { Unit } from 'mol-model/structure'; +import { RepresentationProps, Visual } from '..'; +import { DefaultStructureMeshProps } from '.'; +import { RuntimeContext } from 'mol-task'; +import { PickingId } from '../../util/picking'; +import { LocationIterator } from './visual/util/location-iterator'; +import { Mesh } from '../../shape/mesh'; +import { MarkerData, MarkerAction } from '../../util/marker-data'; +import { Loci } from 'mol-model/loci'; +import { MeshRenderObject } from 'mol-gl/render-object'; +import { createUnitsMeshRenderObject, createColors } from './visual/util/common'; +import { deepEqual } from 'mol-util'; +import { updateMeshValues, updateRenderableState } from '../util'; export interface UnitsVisual<P extends RepresentationProps = {}> extends Visual<Unit.SymmetryGroup, P> { } + +export const DefaultUnitsMeshProps = { + ...DefaultStructureMeshProps, + unitKinds: [ Unit.Kind.Atomic, Unit.Kind.Spheres ] as Unit.Kind[] +} +export type UnitsMeshProps = typeof DefaultUnitsMeshProps + +export interface UnitsMeshVisualBuilder<P extends UnitsMeshProps> { + defaultProps: P + createMesh(ctx: RuntimeContext, unit: Unit, props: P, mesh?: Mesh): Promise<Mesh> + createLocationIterator(group: Unit.SymmetryGroup): LocationIterator + getLoci(pickingId: PickingId, group: Unit.SymmetryGroup, id: number): Loci + mark(loci: Loci, action: MarkerAction, group: Unit.SymmetryGroup, values: MarkerData): void +} + +export function UnitsMeshVisual<P extends UnitsMeshProps>(builder: UnitsMeshVisualBuilder<P>): UnitsVisual<P> { + const { defaultProps, createMesh, createLocationIterator, getLoci, mark } = builder + + let renderObject: MeshRenderObject + let currentProps: P + let mesh: Mesh + let currentGroup: Unit.SymmetryGroup + + return { + get renderObject () { return renderObject }, + async create(ctx: RuntimeContext, group: Unit.SymmetryGroup, props: Partial<P> = {}) { + currentProps = Object.assign({}, defaultProps, props) + currentGroup = group + + const unit = group.units[0] + mesh = currentProps.unitKinds.includes(unit.kind) + ? await createMesh(ctx, unit, currentProps, mesh) + : Mesh.createEmpty(mesh) + + const locationIt = createLocationIterator(group) + renderObject = createUnitsMeshRenderObject(group, mesh, locationIt, currentProps) + }, + async update(ctx: RuntimeContext, props: Partial<P>) { + const newProps = Object.assign({}, currentProps, props) + + if (!renderObject) return false + + let updateColor = false + + // TODO create in-place + // if (currentProps.radialSegments !== newProps.radialSegments) return false + + // TODO + // if (newProps.detail !== currentProps.detail) { + // const unit = currentGroup.units[0] + // const radius = getElementRadius(unit, newProps.sizeTheme) + // mesh = await createElementSphereMesh(ctx, unit, radius, newProps.detail, mesh) + // ValueCell.update(renderObject.values.drawCount, mesh.triangleCount * 3) + // updateColor = true + // } + + if (!deepEqual(newProps.colorTheme, currentProps.colorTheme)) { + updateColor = true + } + + if (updateColor) { + createColors(createLocationIterator(currentGroup), newProps.colorTheme, renderObject.values) + } + + updateMeshValues(renderObject.values, newProps) + updateRenderableState(renderObject.state, newProps) + + currentProps = newProps + return true + }, + getLoci(pickingId: PickingId) { + return getLoci(pickingId, currentGroup, renderObject.id) + }, + mark(loci: Loci, action: MarkerAction) { + mark(loci, action, currentGroup, renderObject.values) + }, + destroy() { + // TODO + } + } +} \ No newline at end of file diff --git a/src/mol-geo/representation/structure/visual/carbohydrate-link-cylinder.ts b/src/mol-geo/representation/structure/visual/carbohydrate-link-cylinder.ts index 1792cf586..73ba9d65e 100644 --- a/src/mol-geo/representation/structure/visual/carbohydrate-link-cylinder.ts +++ b/src/mol-geo/representation/structure/visual/carbohydrate-link-cylinder.ts @@ -6,22 +6,20 @@ import { ValueCell } from 'mol-util/value-cell' -import { MeshRenderObject } from 'mol-gl/render-object' import { Unit, Structure, Link, StructureElement } from 'mol-model/structure'; import { DefaultStructureProps, ComplexVisual } from '..'; import { RuntimeContext } from 'mol-task' -import { createColors, createStructureMeshRenderObject } from './util/common'; import { Mesh } from '../../../shape/mesh'; import { PickingId } from '../../../util/picking'; import { MarkerAction, MarkerData, applyMarkerAction } from '../../../util/marker-data'; import { Loci, EmptyLoci, isEveryLoci } from 'mol-model/loci'; import { SizeTheme } from '../../../theme'; -import { updateMeshValues, updateRenderableState, DefaultMeshProps } from '../../util'; +import { DefaultMeshProps } from '../../util'; import { Vec3 } from 'mol-math/linear-algebra'; -import { deepEqual } from 'mol-util'; import { LocationIterator } from './util/location-iterator'; import { createLinkCylinderMesh, DefaultLinkCylinderProps, LinkCylinderProps } from './util/link'; import { OrderedSet } from 'mol-data/int'; +import { ComplexMeshVisual } from '../complex-visual'; // TODO create seperate visual // for (let i = 0, il = carbohydrates.terminalLinks.length; i < il; ++i) { @@ -61,56 +59,16 @@ export const DefaultCarbohydrateLinkProps = { detail: 0, unitKinds: [ Unit.Kind.Atomic, Unit.Kind.Spheres ] as Unit.Kind[] } -export type CarbohydrateLinkProps = Partial<typeof DefaultCarbohydrateLinkProps> +export type CarbohydrateLinkProps = typeof DefaultCarbohydrateLinkProps export function CarbohydrateLinkVisual(): ComplexVisual<CarbohydrateLinkProps> { - let renderObject: MeshRenderObject - let currentProps: typeof DefaultCarbohydrateLinkProps - let mesh: Mesh - let currentStructure: Structure - - return { - get renderObject () { return renderObject }, - async create(ctx: RuntimeContext, structure: Structure, props: CarbohydrateLinkProps = {}) { - currentProps = Object.assign({}, DefaultCarbohydrateLinkProps, props) - currentStructure = structure - - mesh = await createCarbohydrateLinkCylinderMesh(ctx, currentStructure, currentProps, mesh) - - const locationIt = CarbohydrateLinkIterator(structure) - renderObject = createStructureMeshRenderObject(structure, mesh, locationIt, currentProps) - }, - async update(ctx: RuntimeContext, props: CarbohydrateLinkProps) { - const newProps = Object.assign({}, currentProps, props) - - if (!renderObject) return false - - let updateColor = false - - if (!deepEqual(newProps.colorTheme, currentProps.colorTheme)) { - updateColor = true - } - - if (updateColor) { - createColors(CarbohydrateLinkIterator(currentStructure), newProps.colorTheme, renderObject.values) - } - - updateMeshValues(renderObject.values, newProps) - updateRenderableState(renderObject.state, newProps) - - currentProps = newProps - return false - }, - getLoci(pickingId: PickingId) { - return getLinkLoci(pickingId, currentStructure, renderObject.id) - }, - mark(loci: Loci, action: MarkerAction) { - markLink(loci, action, currentStructure, renderObject.values) - }, - destroy() { - // TODO - } - } + return ComplexMeshVisual<CarbohydrateLinkProps>({ + defaultProps: DefaultCarbohydrateLinkProps, + createMesh: createCarbohydrateLinkCylinderMesh, + createLocationIterator: CarbohydrateLinkIterator, + getLoci: getLinkLoci, + mark: markLink + }) } function CarbohydrateLinkIterator(structure: Structure): LocationIterator { diff --git a/src/mol-geo/representation/structure/visual/carbohydrate-symbol-mesh.ts b/src/mol-geo/representation/structure/visual/carbohydrate-symbol-mesh.ts index f84782fff..5afee10ec 100644 --- a/src/mol-geo/representation/structure/visual/carbohydrate-symbol-mesh.ts +++ b/src/mol-geo/representation/structure/visual/carbohydrate-symbol-mesh.ts @@ -6,29 +6,27 @@ import { ValueCell } from 'mol-util/value-cell' -import { MeshRenderObject } from 'mol-gl/render-object' import { Unit, Structure, StructureElement } from 'mol-model/structure'; import { DefaultStructureProps, ComplexVisual } from '..'; import { RuntimeContext } from 'mol-task' -import { createColors, createStructureMeshRenderObject } from './util/common'; import { Mesh } from '../../../shape/mesh'; import { PickingId } from '../../../util/picking'; import { MarkerAction, MarkerData, applyMarkerAction } from '../../../util/marker-data'; import { Loci, EmptyLoci, isEveryLoci } from 'mol-model/loci'; import { SizeTheme } from '../../../theme'; -import { updateMeshValues, updateRenderableState, DefaultMeshProps } from '../../util'; +import { DefaultMeshProps } from '../../util'; import { MeshBuilder } from '../../../shape/mesh-builder'; import { Vec3, Mat4 } from 'mol-math/linear-algebra'; import { getSaccharideShape, SaccharideShapes } from 'mol-model/structure/structure/carbohydrates/constants'; -import { deepEqual } from 'mol-util'; import { LocationIterator } from './util/location-iterator'; import { OrderedSet } from 'mol-data/int'; +import { ComplexMeshVisual } from '../complex-visual'; const t = Mat4.identity() const sVec = Vec3.zero() const pd = Vec3.zero() -async function createCarbohydrateSymbolMesh(ctx: RuntimeContext, structure: Structure, mesh?: Mesh) { +async function createCarbohydrateSymbolMesh(ctx: RuntimeContext, structure: Structure, props: CarbohydrateSymbolProps, mesh?: Mesh) { const builder = MeshBuilder.create(256, 128, mesh) const carbohydrates = structure.carbohydrates @@ -124,56 +122,16 @@ export const DefaultCarbohydrateSymbolProps = { detail: 0, unitKinds: [ Unit.Kind.Atomic, Unit.Kind.Spheres ] as Unit.Kind[] } -export type CarbohydrateSymbolProps = Partial<typeof DefaultCarbohydrateSymbolProps> +export type CarbohydrateSymbolProps = typeof DefaultCarbohydrateSymbolProps export function CarbohydrateSymbolVisual(): ComplexVisual<CarbohydrateSymbolProps> { - let renderObject: MeshRenderObject - let currentProps: typeof DefaultCarbohydrateSymbolProps - let mesh: Mesh - let currentStructure: Structure - - return { - get renderObject () { return renderObject }, - async create(ctx: RuntimeContext, structure: Structure, props: CarbohydrateSymbolProps = {}) { - currentProps = Object.assign({}, DefaultCarbohydrateSymbolProps, props) - currentStructure = structure - - mesh = await createCarbohydrateSymbolMesh(ctx, currentStructure, mesh) - - const locationIt = CarbohydrateElementIterator(structure) - renderObject = createStructureMeshRenderObject(structure, mesh, locationIt, currentProps) - }, - async update(ctx: RuntimeContext, props: CarbohydrateSymbolProps) { - const newProps = Object.assign({}, currentProps, props) - - if (!renderObject) return false - - let updateColor = false - - if (!deepEqual(newProps.colorTheme, currentProps.colorTheme)) { - updateColor = true - } - - if (updateColor) { - createColors(CarbohydrateElementIterator(currentStructure), newProps.colorTheme, renderObject.values) - } - - updateMeshValues(renderObject.values, newProps) - updateRenderableState(renderObject.state, newProps) - - currentProps = newProps - return false - }, - getLoci(pickingId: PickingId) { - return getCarbohydrateLoci(pickingId, currentStructure, renderObject.id) - }, - mark(loci: Loci, action: MarkerAction) { - markCarbohydrate(loci, action, currentStructure, renderObject.values) - }, - destroy() { - // TODO - } - } + return ComplexMeshVisual<CarbohydrateSymbolProps>({ + defaultProps: DefaultCarbohydrateSymbolProps, + createMesh: createCarbohydrateSymbolMesh, + createLocationIterator: CarbohydrateElementIterator, + getLoci: getCarbohydrateLoci, + mark: markCarbohydrate + }) } function CarbohydrateElementIterator(structure: Structure): LocationIterator { diff --git a/src/mol-geo/representation/structure/visual/cross-link-restraint-cylinder.ts b/src/mol-geo/representation/structure/visual/cross-link-restraint-cylinder.ts index 7a2435546..2942d1d70 100644 --- a/src/mol-geo/representation/structure/visual/cross-link-restraint-cylinder.ts +++ b/src/mol-geo/representation/structure/visual/cross-link-restraint-cylinder.ts @@ -6,23 +6,18 @@ import { ValueCell } from 'mol-util/value-cell' -import { createMeshRenderObject, MeshRenderObject } from 'mol-gl/render-object' import { Link, Structure, StructureElement } from 'mol-model/structure'; import { DefaultStructureProps, ComplexVisual } from '..'; import { RuntimeContext } from 'mol-task' import { LinkCylinderProps, DefaultLinkCylinderProps, createLinkCylinderMesh } from './util/link'; -import { MeshValues } from 'mol-gl/renderable'; -import { getMeshData } from '../../../util/mesh-data'; import { Mesh } from '../../../shape/mesh'; import { PickingId } from '../../../util/picking'; import { Vec3 } from 'mol-math/linear-algebra'; -import { createValueColor } from '../../../util/color-data'; import { Loci, isEveryLoci, EmptyLoci } from 'mol-model/loci'; -import { MarkerAction, applyMarkerAction, createMarkers, MarkerData } from '../../../util/marker-data'; +import { MarkerAction, applyMarkerAction, MarkerData } from '../../../util/marker-data'; import { SizeTheme } from '../../../theme'; -import { createIdentityTransform } from './util/common'; -import { updateMeshValues, updateRenderableState, createMeshValues, createRenderableState } from '../../util'; -// import { chainIdLinkColorData } from '../../../theme/structure/color/chain-id'; +import { ComplexMeshVisual } from '../complex-visual'; +import { LocationIterator } from './util/location-iterator'; async function createCrossLinkRestraintCylinderMesh(ctx: RuntimeContext, structure: Structure, props: LinkCylinderProps, mesh?: Mesh) { @@ -54,66 +49,35 @@ export const DefaultCrossLinkRestraintProps = { flipSided: false, flatShaded: false, } -export type CrossLinkRestraintProps = Partial<typeof DefaultCrossLinkRestraintProps> +export type CrossLinkRestraintProps = typeof DefaultCrossLinkRestraintProps -export function CrossLinkRestraintVisual(): ComplexVisual<CrossLinkRestraintProps> { - let renderObject: MeshRenderObject - let currentProps: typeof DefaultCrossLinkRestraintProps - let mesh: Mesh - let currentStructure: Structure - - return { - get renderObject () { return renderObject }, - async create(ctx: RuntimeContext, structure: Structure, props: CrossLinkRestraintProps = {}) { - currentProps = Object.assign({}, DefaultCrossLinkRestraintProps, props) - currentStructure = structure - - const elementCount = structure.crossLinkRestraints.count - const instanceCount = 1 - - mesh = await createCrossLinkRestraintCylinderMesh(ctx, structure, currentProps) - - const transforms = createIdentityTransform() - const color = createValueColor(0x119911) // TODO - const marker = createMarkers(instanceCount * elementCount) - - const counts = { drawCount: mesh.triangleCount * 3, elementCount, instanceCount } - - const values: MeshValues = { - ...getMeshData(mesh), - ...color, - ...marker, - aTransform: transforms, - elements: mesh.indexBuffer, - ...createMeshValues(currentProps, counts), - } - const state = createRenderableState(currentProps) - - renderObject = createMeshRenderObject(values, state) - }, - async update(ctx: RuntimeContext, props: CrossLinkRestraintProps) { - const newProps = Object.assign({}, currentProps, props) +// TODO update & create in-place +// if (currentProps.radialSegments !== newProps.radialSegments) return false - if (!renderObject) return false - - // TODO create in-place - if (currentProps.radialSegments !== newProps.radialSegments) return false - - updateMeshValues(renderObject.values, newProps) - updateRenderableState(renderObject.state, newProps) +export function CrossLinkRestraintVisual(): ComplexVisual<CrossLinkRestraintProps> { + return ComplexMeshVisual<CrossLinkRestraintProps>({ + defaultProps: DefaultCrossLinkRestraintProps, + createMesh: createCrossLinkRestraintCylinderMesh, + createLocationIterator: CrossLinkRestraintIterator, + getLoci: getLinkLoci, + mark: markLink + }) +} - return false - }, - getLoci(pickingId: PickingId) { - return getLinkLoci(pickingId, currentStructure, renderObject.id) - }, - mark(loci: Loci, action: MarkerAction) { - markLink(loci, action, currentStructure, renderObject.values) - }, - destroy() { - // TODO - } +function CrossLinkRestraintIterator(structure: Structure): LocationIterator { + const { pairs } = structure.crossLinkRestraints + const elementCount = pairs.length + const instanceCount = 1 + const location = Link.Location() + const getLocation = (elementIndex: number, instanceIndex: number) => { + const pair = pairs[elementIndex] + location.aUnit = pair.unitA + location.aIndex = pair.indexA + location.bUnit = pair.unitB + location.bIndex = pair.indexB + return location } + return LocationIterator(elementCount, instanceCount, getLocation) } function getLinkLoci(pickingId: PickingId, structure: Structure, id: number) { diff --git a/src/mol-geo/representation/structure/visual/element-point.ts b/src/mol-geo/representation/structure/visual/element-point.ts index 55a4b30eb..d512c3048 100644 --- a/src/mol-geo/representation/structure/visual/element-point.ts +++ b/src/mol-geo/representation/structure/visual/element-point.ts @@ -130,10 +130,10 @@ export default function PointVisual(): UnitsVisual<PointProps> { return false }, getLoci(pickingId: PickingId) { - return getElementLoci(renderObject.id, currentGroup, pickingId) + return getElementLoci(pickingId, currentGroup, renderObject.id) }, mark(loci: Loci, action: MarkerAction) { - markElement(renderObject.values.tMarker, currentGroup, loci, action) + markElement(loci, action, currentGroup, renderObject.values) }, destroy() { // TODO diff --git a/src/mol-geo/representation/structure/visual/element-sphere.ts b/src/mol-geo/representation/structure/visual/element-sphere.ts index 48735943b..6b5c78cc1 100644 --- a/src/mol-geo/representation/structure/visual/element-sphere.ts +++ b/src/mol-geo/representation/structure/visual/element-sphere.ts @@ -5,92 +5,23 @@ * @author David Sehnal <david.sehnal@gmail.com> */ -import { ValueCell } from 'mol-util/value-cell' - -import { MeshRenderObject } from 'mol-gl/render-object' -import { Unit } from 'mol-model/structure'; -import { DefaultStructureProps, UnitsVisual } from '..'; -import { RuntimeContext } from 'mol-task' -import { createColors, createUnitsMeshRenderObject } from './util/common'; -import { createElementSphereMesh, markElement, getElementRadius, getElementLoci } from './util/element'; -import { deepEqual } from 'mol-util'; -import { Mesh } from '../../../shape/mesh'; -import { PickingId } from '../../../util/picking'; -import { MarkerAction } from '../../../util/marker-data'; -import { Loci } from 'mol-model/loci'; -import { SizeTheme } from '../../../theme'; -import { updateMeshValues, updateRenderableState, DefaultMeshProps } from '../../util'; +import { UnitsVisual } from '..'; +import { createElementSphereMesh, markElement, getElementLoci } from './util/element'; import { StructureElementIterator } from './util/location-iterator'; +import { UnitsMeshVisual, DefaultUnitsMeshProps } from '../units-visual'; export const DefaultElementSphereProps = { - ...DefaultMeshProps, - ...DefaultStructureProps, - sizeTheme: { name: 'physical', factor: 1 } as SizeTheme, - detail: 0, - unitKinds: [ Unit.Kind.Atomic, Unit.Kind.Spheres ] as Unit.Kind[] + ...DefaultUnitsMeshProps, + detail: 0 } -export type ElementSphereProps = Partial<typeof DefaultElementSphereProps> +export type ElementSphereProps = typeof DefaultElementSphereProps export function ElementSphereVisual(): UnitsVisual<ElementSphereProps> { - let renderObject: MeshRenderObject - let currentProps: typeof DefaultElementSphereProps - let mesh: Mesh - let currentGroup: Unit.SymmetryGroup - - return { - get renderObject () { return renderObject }, - async create(ctx: RuntimeContext, group: Unit.SymmetryGroup, props: ElementSphereProps = {}) { - currentProps = Object.assign({}, DefaultElementSphereProps, props) - currentGroup = group - - const { detail, sizeTheme, unitKinds } = { ...DefaultElementSphereProps, ...props } - const unit = group.units[0] - - const radius = getElementRadius(unit, sizeTheme) - mesh = unitKinds.includes(unit.kind) - ? await createElementSphereMesh(ctx, unit, radius, detail, mesh) - : Mesh.createEmpty(mesh) - - const locationIt = StructureElementIterator.fromGroup(group) - renderObject = createUnitsMeshRenderObject(group, mesh, locationIt, currentProps) - }, - async update(ctx: RuntimeContext, props: ElementSphereProps) { - const newProps = Object.assign({}, currentProps, props) - - if (!renderObject) return false - - let updateColor = false - - if (newProps.detail !== currentProps.detail) { - const unit = currentGroup.units[0] - const radius = getElementRadius(unit, newProps.sizeTheme) - mesh = await createElementSphereMesh(ctx, unit, radius, newProps.detail, mesh) - ValueCell.update(renderObject.values.drawCount, mesh.triangleCount * 3) - updateColor = true - } - - if (!deepEqual(newProps.colorTheme, currentProps.colorTheme)) { - updateColor = true - } - - if (updateColor) { - createColors(StructureElementIterator.fromGroup(currentGroup), newProps.colorTheme, renderObject.values) - } - - updateMeshValues(renderObject.values, newProps) - updateRenderableState(renderObject.state, newProps) - - currentProps = newProps - return true - }, - getLoci(pickingId: PickingId) { - return getElementLoci(renderObject.id, currentGroup, pickingId) - }, - mark(loci: Loci, action: MarkerAction) { - markElement(renderObject.values.tMarker, currentGroup, loci, action) - }, - destroy() { - // TODO - } - } -} + return UnitsMeshVisual<ElementSphereProps>({ + defaultProps: DefaultElementSphereProps, + createMesh: createElementSphereMesh, + createLocationIterator: StructureElementIterator.fromGroup, + getLoci: getElementLoci, + mark: markElement + }) +} \ No newline at end of file diff --git a/src/mol-geo/representation/structure/visual/inter-unit-link-cylinder.ts b/src/mol-geo/representation/structure/visual/inter-unit-link-cylinder.ts index 7587b44fa..0285609bf 100644 --- a/src/mol-geo/representation/structure/visual/inter-unit-link-cylinder.ts +++ b/src/mol-geo/representation/structure/visual/inter-unit-link-cylinder.ts @@ -6,7 +6,6 @@ import { ValueCell } from 'mol-util/value-cell' -import { MeshRenderObject } from 'mol-gl/render-object' import { Link, Structure, StructureElement } from 'mol-model/structure'; import { DefaultStructureProps, ComplexVisual } from '..'; import { RuntimeContext } from 'mol-task' @@ -17,10 +16,8 @@ import { Vec3 } from 'mol-math/linear-algebra'; import { Loci, isEveryLoci, EmptyLoci } from 'mol-model/loci'; import { MarkerAction, applyMarkerAction, MarkerData } from '../../../util/marker-data'; import { SizeTheme } from '../../../theme'; -import { createColors, createStructureMeshRenderObject } from './util/common'; -import { updateMeshValues, updateRenderableState } from '../../util'; import { LinkIterator } from './util/location-iterator'; -import { deepEqual } from 'mol-util'; +import { ComplexMeshVisual } from '../complex-visual'; async function createInterUnitLinkCylinderMesh(ctx: RuntimeContext, structure: Structure, props: LinkCylinderProps, mesh?: Mesh) { const links = structure.links @@ -49,59 +46,16 @@ export const DefaultInterUnitLinkProps = { ...DefaultLinkCylinderProps, sizeTheme: { name: 'physical', factor: 0.3 } as SizeTheme, } -export type InterUnitLinkProps = Partial<typeof DefaultInterUnitLinkProps> +export type InterUnitLinkProps = typeof DefaultInterUnitLinkProps export function InterUnitLinkVisual(): ComplexVisual<InterUnitLinkProps> { - let renderObject: MeshRenderObject - let currentProps: typeof DefaultInterUnitLinkProps - let mesh: Mesh - let currentStructure: Structure - - return { - get renderObject () { return renderObject }, - async create(ctx: RuntimeContext, structure: Structure, props: InterUnitLinkProps = {}) { - currentProps = Object.assign({}, DefaultInterUnitLinkProps, props) - currentStructure = structure - - mesh = await createInterUnitLinkCylinderMesh(ctx, structure, currentProps) - - const locationIt = LinkIterator.fromStructure(structure) - renderObject = createStructureMeshRenderObject(structure, mesh, locationIt, currentProps) - }, - async update(ctx: RuntimeContext, props: InterUnitLinkProps) { - const newProps = Object.assign({}, currentProps, props) - - if (!renderObject) return false - - let updateColor = false - - // TODO create in-place - if (currentProps.radialSegments !== newProps.radialSegments) return false - - if (!deepEqual(newProps.colorTheme, currentProps.colorTheme)) { - updateColor = true - } - - if (updateColor) { - createColors(LinkIterator.fromStructure(currentStructure), newProps.colorTheme, renderObject.values) - } - - updateMeshValues(renderObject.values, newProps) - updateRenderableState(renderObject.state, newProps) - - currentProps = newProps - return false - }, - getLoci(pickingId: PickingId) { - return getLinkLoci(pickingId, currentStructure, renderObject.id) - }, - mark(loci: Loci, action: MarkerAction) { - markLink(loci, action, currentStructure, renderObject.values) - }, - destroy() { - // TODO - } - } + return ComplexMeshVisual<InterUnitLinkProps>({ + defaultProps: DefaultInterUnitLinkProps, + createMesh: createInterUnitLinkCylinderMesh, + createLocationIterator: LinkIterator.fromStructure, + getLoci: getLinkLoci, + mark: markLink + }) } function getLinkLoci(pickingId: PickingId, structure: Structure, id: number) { diff --git a/src/mol-geo/representation/structure/visual/intra-unit-link-cylinder.ts b/src/mol-geo/representation/structure/visual/intra-unit-link-cylinder.ts index 34db658a1..d9c66bd1b 100644 --- a/src/mol-geo/representation/structure/visual/intra-unit-link-cylinder.ts +++ b/src/mol-geo/representation/structure/visual/intra-unit-link-cylinder.ts @@ -7,22 +7,18 @@ import { ValueCell } from 'mol-util/value-cell' -import { MeshRenderObject } from 'mol-gl/render-object' import { Unit, Link, StructureElement } from 'mol-model/structure'; -import { UnitsVisual, DefaultStructureProps } from '..'; +import { UnitsVisual } from '..'; import { RuntimeContext } from 'mol-task' import { DefaultLinkCylinderProps, LinkCylinderProps, createLinkCylinderMesh } from './util/link'; import { Mesh } from '../../../shape/mesh'; import { PickingId } from '../../../util/picking'; import { Vec3 } from 'mol-math/linear-algebra'; -// import { createUniformColor } from '../../../util/color-data'; import { Loci, isEveryLoci, EmptyLoci } from 'mol-model/loci'; import { MarkerAction, applyMarkerAction, MarkerData } from '../../../util/marker-data'; import { SizeTheme } from '../../../theme'; -import { createColors, createUnitsMeshRenderObject } from './util/common'; -import { updateMeshValues, updateRenderableState, DefaultMeshProps } from '../../util'; import { LinkIterator } from './util/location-iterator'; -import { deepEqual } from 'mol-util'; +import { UnitsMeshVisual, DefaultUnitsMeshProps } from '../units-visual'; async function createIntraUnitLinkCylinderMesh(ctx: RuntimeContext, unit: Unit, props: LinkCylinderProps, mesh?: Mesh) { if (!Unit.isAtomic(unit)) return Mesh.createEmpty(mesh) @@ -62,65 +58,20 @@ async function createIntraUnitLinkCylinderMesh(ctx: RuntimeContext, unit: Unit, } export const DefaultIntraUnitLinkProps = { - ...DefaultMeshProps, - ...DefaultStructureProps, + ...DefaultUnitsMeshProps, ...DefaultLinkCylinderProps, sizeTheme: { name: 'physical', factor: 0.3 } as SizeTheme, } -export type IntraUnitLinkProps = Partial<typeof DefaultIntraUnitLinkProps> +export type IntraUnitLinkProps = typeof DefaultIntraUnitLinkProps export function IntraUnitLinkVisual(): UnitsVisual<IntraUnitLinkProps> { - let renderObject: MeshRenderObject - let currentProps: typeof DefaultIntraUnitLinkProps - let mesh: Mesh - let currentGroup: Unit.SymmetryGroup - - return { - get renderObject () { return renderObject }, - async create(ctx: RuntimeContext, group: Unit.SymmetryGroup, props: IntraUnitLinkProps = {}) { - currentProps = Object.assign({}, DefaultIntraUnitLinkProps, props) - currentGroup = group - - const unit = group.units[0] - mesh = await createIntraUnitLinkCylinderMesh(ctx, unit, currentProps) - - const locationIt = LinkIterator.fromGroup(group) - renderObject = createUnitsMeshRenderObject(group, mesh, locationIt, currentProps) - }, - async update(ctx: RuntimeContext, props: IntraUnitLinkProps) { - const newProps = Object.assign({}, currentProps, props) - - if (!renderObject) return false - - let updateColor = false - - // TODO create in-place - if (currentProps.radialSegments !== newProps.radialSegments) return false - - if (!deepEqual(newProps.colorTheme, currentProps.colorTheme)) { - updateColor = true - } - - if (updateColor) { - createColors(LinkIterator.fromGroup(currentGroup), newProps.colorTheme, renderObject.values) - } - - updateMeshValues(renderObject.values, newProps) - updateRenderableState(renderObject.state, newProps) - - currentProps = newProps - return true - }, - getLoci(pickingId: PickingId) { - return getLinkLoci(pickingId, currentGroup, renderObject.id) - }, - mark(loci: Loci, action: MarkerAction) { - markLink(loci, action, currentGroup, renderObject.values) - }, - destroy() { - // TODO - } - } + return UnitsMeshVisual<IntraUnitLinkProps>({ + defaultProps: DefaultIntraUnitLinkProps, + createMesh: createIntraUnitLinkCylinderMesh, + createLocationIterator: LinkIterator.fromGroup, + getLoci: getLinkLoci, + mark: markLink + }) } function getLinkLoci(pickingId: PickingId, group: Unit.SymmetryGroup, id: number) { diff --git a/src/mol-geo/representation/structure/visual/nucleotide-block-mesh.ts b/src/mol-geo/representation/structure/visual/nucleotide-block-mesh.ts index 7f76cf611..3bd6af749 100644 --- a/src/mol-geo/representation/structure/visual/nucleotide-block-mesh.ts +++ b/src/mol-geo/representation/structure/visual/nucleotide-block-mesh.ts @@ -4,20 +4,10 @@ * @author Alexander Rose <alexander.rose@weirdbyte.de> */ -import { ValueCell } from 'mol-util/value-cell' - -import { MeshRenderObject } from 'mol-gl/render-object' import { Unit } from 'mol-model/structure'; -import { DefaultStructureProps, UnitsVisual } from '..'; +import { UnitsVisual } from '..'; import { RuntimeContext } from 'mol-task' -import { createColors, createUnitsMeshRenderObject } from './util/common'; -import { deepEqual } from 'mol-util'; import { Mesh } from '../../../shape/mesh'; -import { PickingId } from '../../../util/picking'; -import { MarkerAction } from '../../../util/marker-data'; -import { Loci } from 'mol-model/loci'; -import { SizeTheme } from '../../../theme'; -import { updateMeshValues, updateRenderableState, DefaultMeshProps } from '../../util'; import { MeshBuilder } from '../../../shape/mesh-builder'; import { getElementLoci, markElement } from './util/element'; import { Vec3, Mat4 } from 'mol-math/linear-algebra'; @@ -25,6 +15,7 @@ import { Segmentation, SortedArray } from 'mol-data/int'; import { MoleculeType, isNucleic, isPurinBase, isPyrimidineBase } from 'mol-model/structure/model/types'; import { getElementIndexForAtomId, getElementIndexForAtomRole } from 'mol-model/structure/util'; import { StructureElementIterator } from './util/location-iterator'; +import { DefaultUnitsMeshProps, UnitsMeshVisual } from '../units-visual'; const p1 = Vec3.zero() const p2 = Vec3.zero() @@ -39,7 +30,7 @@ const center = Vec3.zero() const t = Mat4.identity() const sVec = Vec3.zero() -async function createNucleotideBlockMesh(ctx: RuntimeContext, unit: Unit, mesh?: Mesh) { +async function createNucleotideBlockMesh(ctx: RuntimeContext, unit: Unit, props: {}, mesh?: Mesh) { if (!Unit.isAtomic(unit)) return Mesh.createEmpty(mesh) const builder = MeshBuilder.create(256, 128, mesh) @@ -113,73 +104,16 @@ async function createNucleotideBlockMesh(ctx: RuntimeContext, unit: Unit, mesh?: } export const DefaultNucleotideBlockProps = { - ...DefaultMeshProps, - ...DefaultStructureProps, - sizeTheme: { name: 'physical', factor: 1 } as SizeTheme, - detail: 0, - unitKinds: [ Unit.Kind.Atomic, Unit.Kind.Spheres ] as Unit.Kind[] + ...DefaultUnitsMeshProps } -export type NucleotideBlockProps = Partial<typeof DefaultNucleotideBlockProps> +export type NucleotideBlockProps = typeof DefaultNucleotideBlockProps export function NucleotideBlockVisual(): UnitsVisual<NucleotideBlockProps> { - let renderObject: MeshRenderObject - let currentProps: typeof DefaultNucleotideBlockProps - let mesh: Mesh - let currentGroup: Unit.SymmetryGroup - - return { - get renderObject () { return renderObject }, - async create(ctx: RuntimeContext, group: Unit.SymmetryGroup, props: NucleotideBlockProps = {}) { - currentProps = Object.assign({}, DefaultNucleotideBlockProps, props) - currentGroup = group - - const { unitKinds } = { ...DefaultNucleotideBlockProps, ...props } - const unit = group.units[0] - - mesh = unitKinds.includes(unit.kind) - ? await createNucleotideBlockMesh(ctx, unit, mesh) - : Mesh.createEmpty(mesh) - - const locationIt = StructureElementIterator.fromGroup(group) - renderObject = createUnitsMeshRenderObject(group, mesh, locationIt, currentProps) - }, - async update(ctx: RuntimeContext, props: NucleotideBlockProps) { - const newProps = Object.assign({}, currentProps, props) - - if (!renderObject) return false - - let updateColor = false - - if (newProps.detail !== currentProps.detail) { - const unit = currentGroup.units[0] - mesh = await createNucleotideBlockMesh(ctx, unit, mesh) - ValueCell.update(renderObject.values.drawCount, mesh.triangleCount * 3) - updateColor = true - } - - if (!deepEqual(newProps.colorTheme, currentProps.colorTheme)) { - updateColor = true - } - - if (updateColor) { - if (ctx.shouldUpdate) await ctx.update('Computing nucleotide block colors'); - createColors(StructureElementIterator.fromGroup(currentGroup), newProps.colorTheme, renderObject.values) - } - - updateMeshValues(renderObject.values, newProps) - updateRenderableState(renderObject.state, newProps) - - currentProps = newProps - return true - }, - getLoci(pickingId: PickingId) { - return getElementLoci(renderObject.id, currentGroup, pickingId) - }, - mark(loci: Loci, action: MarkerAction) { - markElement(renderObject.values.tMarker, currentGroup, loci, action) - }, - destroy() { - // TODO - } - } -} + return UnitsMeshVisual<NucleotideBlockProps>({ + defaultProps: DefaultNucleotideBlockProps, + createMesh: createNucleotideBlockMesh, + createLocationIterator: StructureElementIterator.fromGroup, + getLoci: getElementLoci, + mark: markElement + }) +} \ No newline at end of file diff --git a/src/mol-geo/representation/structure/visual/polymer-backbone-cylinder.ts b/src/mol-geo/representation/structure/visual/polymer-backbone-cylinder.ts index 2956a9d8e..1cf481582 100644 --- a/src/mol-geo/representation/structure/visual/polymer-backbone-cylinder.ts +++ b/src/mol-geo/representation/structure/visual/polymer-backbone-cylinder.ts @@ -4,27 +4,18 @@ * @author Alexander Rose <alexander.rose@weirdbyte.de> */ -import { ValueCell } from 'mol-util/value-cell' - -import { MeshRenderObject } from 'mol-gl/render-object' import { Unit } from 'mol-model/structure'; -import { DefaultStructureProps, UnitsVisual } from '..'; +import { UnitsVisual } from '..'; import { RuntimeContext } from 'mol-task' -import { createColors, createUnitsMeshRenderObject } from './util/common'; -import { deepEqual } from 'mol-util'; import { Mesh } from '../../../shape/mesh'; -import { PickingId } from '../../../util/picking'; -import { MarkerAction } from '../../../util/marker-data'; -import { Loci } from 'mol-model/loci'; -import { SizeTheme } from '../../../theme'; -import { updateMeshValues, updateRenderableState, DefaultMeshProps } from '../../util'; import { MeshBuilder } from '../../../shape/mesh-builder'; import { getPolymerElementCount, PolymerBackboneIterator } from './util/polymer'; import { getElementLoci, markElement } from './util/element'; import { Vec3 } from 'mol-math/linear-algebra'; import { StructureElementIterator } from './util/location-iterator'; +import { DefaultUnitsMeshProps, UnitsMeshVisual } from '../units-visual'; -async function createPolymerBackboneCylinderMesh(ctx: RuntimeContext, unit: Unit, mesh?: Mesh) { +async function createPolymerBackboneCylinderMesh(ctx: RuntimeContext, unit: Unit, props: {}, mesh?: Mesh) { const polymerElementCount = getPolymerElementCount(unit) if (!polymerElementCount) return Mesh.createEmpty(mesh) console.log('polymerElementCount backbone', polymerElementCount) @@ -59,73 +50,16 @@ async function createPolymerBackboneCylinderMesh(ctx: RuntimeContext, unit: Unit } export const DefaultPolymerBackboneProps = { - ...DefaultMeshProps, - ...DefaultStructureProps, - sizeTheme: { name: 'physical', factor: 1 } as SizeTheme, - detail: 0, - unitKinds: [ Unit.Kind.Atomic, Unit.Kind.Spheres ] as Unit.Kind[] + ...DefaultUnitsMeshProps } -export type PolymerBackboneProps = Partial<typeof DefaultPolymerBackboneProps> +export type PolymerBackboneProps = typeof DefaultPolymerBackboneProps export function PolymerBackboneVisual(): UnitsVisual<PolymerBackboneProps> { - let renderObject: MeshRenderObject - let currentProps: typeof DefaultPolymerBackboneProps - let mesh: Mesh - let currentGroup: Unit.SymmetryGroup - - return { - get renderObject () { return renderObject }, - async create(ctx: RuntimeContext, group: Unit.SymmetryGroup, props: PolymerBackboneProps = {}) { - currentProps = Object.assign({}, DefaultPolymerBackboneProps, props) - currentGroup = group - - const { unitKinds } = { ...DefaultPolymerBackboneProps, ...props } - const unit = group.units[0] - - mesh = unitKinds.includes(unit.kind) - ? await createPolymerBackboneCylinderMesh(ctx, unit, mesh) - : Mesh.createEmpty(mesh) - - const locationIt = StructureElementIterator.fromGroup(group) - renderObject = createUnitsMeshRenderObject(group, mesh, locationIt, currentProps) - }, - async update(ctx: RuntimeContext, props: PolymerBackboneProps) { - const newProps = Object.assign({}, currentProps, props) - - if (!renderObject) return false - - let updateColor = false - - if (newProps.detail !== currentProps.detail) { - const unit = currentGroup.units[0] - mesh = await createPolymerBackboneCylinderMesh(ctx, unit, mesh) - ValueCell.update(renderObject.values.drawCount, mesh.triangleCount * 3) - updateColor = true - } - - if (!deepEqual(newProps.colorTheme, currentProps.colorTheme)) { - updateColor = true - } - - if (updateColor) { - if (ctx.shouldUpdate) await ctx.update('Computing trace colors'); - createColors(StructureElementIterator.fromGroup(currentGroup), newProps.colorTheme, renderObject.values) - } - - updateMeshValues(renderObject.values, newProps) - updateRenderableState(renderObject.state, newProps) - - currentProps = newProps - return true - }, - getLoci(pickingId: PickingId) { - return getElementLoci(renderObject.id, currentGroup, pickingId) - }, - mark(loci: Loci, action: MarkerAction) { - markElement(renderObject.values.tMarker, currentGroup, loci, action) - }, - destroy() { - // TODO - } - } -} + return UnitsMeshVisual<PolymerBackboneProps>({ + defaultProps: DefaultPolymerBackboneProps, + createMesh: createPolymerBackboneCylinderMesh, + createLocationIterator: StructureElementIterator.fromGroup, + getLoci: getElementLoci, + mark: markElement + }) +} \ No newline at end of file diff --git a/src/mol-geo/representation/structure/visual/polymer-direction-wedge.ts b/src/mol-geo/representation/structure/visual/polymer-direction-wedge.ts index 926d76775..3ac265684 100644 --- a/src/mol-geo/representation/structure/visual/polymer-direction-wedge.ts +++ b/src/mol-geo/representation/structure/visual/polymer-direction-wedge.ts @@ -4,27 +4,17 @@ * @author Alexander Rose <alexander.rose@weirdbyte.de> */ -import { ValueCell } from 'mol-util/value-cell' - -import { MeshRenderObject } from 'mol-gl/render-object' -import { Unit, StructureElement } from 'mol-model/structure'; -import { DefaultStructureProps, UnitsVisual } from '..'; +import { Unit } from 'mol-model/structure'; +import { UnitsVisual } from '..'; import { RuntimeContext } from 'mol-task' -import { createColors, createUnitsMeshRenderObject } from './util/common'; -import { markElement } from './util/element'; -import { deepEqual } from 'mol-util'; +import { markElement, getElementLoci } from './util/element'; import { Mesh } from '../../../shape/mesh'; -import { PickingId } from '../../../util/picking'; -import { OrderedSet } from 'mol-data/int'; -import { MarkerAction } from '../../../util/marker-data'; -import { Loci, EmptyLoci } from 'mol-model/loci'; -import { SizeTheme } from '../../../theme'; -import { updateMeshValues, updateRenderableState, DefaultMeshProps } from '../../util'; import { MeshBuilder } from '../../../shape/mesh-builder'; import { getPolymerElementCount, PolymerTraceIterator, createCurveSegmentState, interpolateCurveSegment } from './util/polymer'; import { Vec3, Mat4 } from 'mol-math/linear-algebra'; import { SecondaryStructureType, MoleculeType } from 'mol-model/structure/model/types'; import { StructureElementIterator } from './util/location-iterator'; +import { DefaultUnitsMeshProps, UnitsMeshVisual } from '../units-visual'; const t = Mat4.identity() const sVec = Vec3.zero() @@ -32,7 +22,7 @@ const n0 = Vec3.zero() const n1 = Vec3.zero() const upVec = Vec3.zero() -async function createPolymerDirectionWedgeMesh(ctx: RuntimeContext, unit: Unit, mesh?: Mesh) { +async function createPolymerDirectionWedgeMesh(ctx: RuntimeContext, unit: Unit, props: {}, mesh?: Mesh) { const polymerElementCount = getPolymerElementCount(unit) console.log('polymerElementCount direction', polymerElementCount) if (!polymerElementCount) return Mesh.createEmpty(mesh) @@ -87,79 +77,16 @@ async function createPolymerDirectionWedgeMesh(ctx: RuntimeContext, unit: Unit, } export const DefaultPolymerDirectionProps = { - ...DefaultMeshProps, - ...DefaultStructureProps, - sizeTheme: { name: 'physical', factor: 1 } as SizeTheme, - detail: 0, - unitKinds: [ Unit.Kind.Atomic, Unit.Kind.Spheres ] as Unit.Kind[] + ...DefaultUnitsMeshProps } -export type PolymerDirectionProps = Partial<typeof DefaultPolymerDirectionProps> +export type PolymerDirectionProps = typeof DefaultPolymerDirectionProps export function PolymerDirectionVisual(): UnitsVisual<PolymerDirectionProps> { - let renderObject: MeshRenderObject - let currentProps: typeof DefaultPolymerDirectionProps - let mesh: Mesh - let currentGroup: Unit.SymmetryGroup - - return { - get renderObject () { return renderObject }, - async create(ctx: RuntimeContext, group: Unit.SymmetryGroup, props: PolymerDirectionProps = {}) { - currentProps = Object.assign({}, DefaultPolymerDirectionProps, props) - currentGroup = group - - const { unitKinds } = { ...DefaultPolymerDirectionProps, ...props } - const unit = group.units[0] - - mesh = unitKinds.includes(unit.kind) - ? await createPolymerDirectionWedgeMesh(ctx, unit, mesh) - : Mesh.createEmpty(mesh) - - const locationIt = StructureElementIterator.fromGroup(group) - renderObject = createUnitsMeshRenderObject(group, mesh, locationIt, currentProps) - }, - async update(ctx: RuntimeContext, props: PolymerDirectionProps) { - const newProps = Object.assign({}, currentProps, props) - - if (!renderObject) return false - - let updateColor = false - - if (newProps.detail !== currentProps.detail) { - const unit = currentGroup.units[0] - mesh = await createPolymerDirectionWedgeMesh(ctx, unit, mesh) - ValueCell.update(renderObject.values.drawCount, mesh.triangleCount * 3) - updateColor = true - } - - if (!deepEqual(newProps.colorTheme, currentProps.colorTheme)) { - updateColor = true - } - - if (updateColor) { - if (ctx.shouldUpdate) await ctx.update('Computing direction colors'); - createColors(StructureElementIterator.fromGroup(currentGroup), newProps.colorTheme, renderObject.values) - } - - updateMeshValues(renderObject.values, newProps) - updateRenderableState(renderObject.state, newProps) - - currentProps = newProps - return true - }, - getLoci(pickingId: PickingId) { - const { objectId, instanceId, elementId } = pickingId - if (renderObject.id === objectId) { - const unit = currentGroup.units[instanceId] - const indices = OrderedSet.ofSingleton(elementId as StructureElement.UnitIndex); - return StructureElement.Loci([{ unit, indices }]) - } - return EmptyLoci - }, - mark(loci: Loci, action: MarkerAction) { - markElement(renderObject.values.tMarker, currentGroup, loci, action) - }, - destroy() { - // TODO - } - } -} + return UnitsMeshVisual<PolymerDirectionProps>({ + defaultProps: DefaultPolymerDirectionProps, + createMesh: createPolymerDirectionWedgeMesh, + createLocationIterator: StructureElementIterator.fromGroup, + getLoci: getElementLoci, + mark: markElement + }) +} \ No newline at end of file diff --git a/src/mol-geo/representation/structure/visual/polymer-gap-cylinder.ts b/src/mol-geo/representation/structure/visual/polymer-gap-cylinder.ts index 5c9dc9668..172b2b52f 100644 --- a/src/mol-geo/representation/structure/visual/polymer-gap-cylinder.ts +++ b/src/mol-geo/representation/structure/visual/polymer-gap-cylinder.ts @@ -4,27 +4,18 @@ * @author Alexander Rose <alexander.rose@weirdbyte.de> */ -import { ValueCell } from 'mol-util/value-cell' - -import { MeshRenderObject } from 'mol-gl/render-object' import { Unit } from 'mol-model/structure'; -import { DefaultStructureProps, UnitsVisual } from '..'; +import { UnitsVisual } from '..'; import { RuntimeContext } from 'mol-task' -import { createColors, createUnitsMeshRenderObject } from './util/common'; -import { deepEqual } from 'mol-util'; import { Mesh } from '../../../shape/mesh'; -import { PickingId } from '../../../util/picking'; -import { MarkerAction } from '../../../util/marker-data'; -import { Loci } from 'mol-model/loci'; -import { SizeTheme } from '../../../theme'; -import { updateMeshValues, updateRenderableState, DefaultMeshProps } from '../../util'; import { MeshBuilder } from '../../../shape/mesh-builder'; import { getPolymerGapCount, PolymerGapIterator } from './util/polymer'; import { getElementLoci, markElement } from './util/element'; import { Vec3 } from 'mol-math/linear-algebra'; import { StructureElementIterator } from './util/location-iterator'; +import { UnitsMeshVisual, DefaultUnitsMeshProps } from '../units-visual'; -async function createPolymerGapCylinderMesh(ctx: RuntimeContext, unit: Unit, mesh?: Mesh) { +async function createPolymerGapCylinderMesh(ctx: RuntimeContext, unit: Unit, props: {}, mesh?: Mesh) { const polymerGapCount = getPolymerGapCount(unit) if (!polymerGapCount) return Mesh.createEmpty(mesh) console.log('polymerGapCount', polymerGapCount) @@ -65,73 +56,16 @@ async function createPolymerGapCylinderMesh(ctx: RuntimeContext, unit: Unit, mes } export const DefaultPolymerGapProps = { - ...DefaultMeshProps, - ...DefaultStructureProps, - sizeTheme: { name: 'physical', factor: 1 } as SizeTheme, - detail: 0, - unitKinds: [ Unit.Kind.Atomic, Unit.Kind.Spheres ] as Unit.Kind[] + ...DefaultUnitsMeshProps } -export type PolymerGapProps = Partial<typeof DefaultPolymerGapProps> +export type PolymerGapProps = typeof DefaultPolymerGapProps export function PolymerGapVisual(): UnitsVisual<PolymerGapProps> { - let renderObject: MeshRenderObject - let currentProps: typeof DefaultPolymerGapProps - let mesh: Mesh - let currentGroup: Unit.SymmetryGroup - - return { - get renderObject () { return renderObject }, - async create(ctx: RuntimeContext, group: Unit.SymmetryGroup, props: PolymerGapProps = {}) { - currentProps = Object.assign({}, DefaultPolymerGapProps, props) - currentGroup = group - - const { unitKinds } = { ...DefaultPolymerGapProps, ...props } - const unit = group.units[0] - - mesh = unitKinds.includes(unit.kind) - ? await createPolymerGapCylinderMesh(ctx, unit, mesh) - : Mesh.createEmpty(mesh) - - const locationIt = StructureElementIterator.fromGroup(group) - renderObject = createUnitsMeshRenderObject(group, mesh, locationIt, currentProps) - }, - async update(ctx: RuntimeContext, props: PolymerGapProps) { - const newProps = Object.assign({}, currentProps, props) - - if (!renderObject) return false - - let updateColor = false - - if (newProps.detail !== currentProps.detail) { - const unit = currentGroup.units[0] - mesh = await createPolymerGapCylinderMesh(ctx, unit, mesh) - ValueCell.update(renderObject.values.drawCount, mesh.triangleCount * 3) - updateColor = true - } - - if (!deepEqual(newProps.colorTheme, currentProps.colorTheme)) { - updateColor = true - } - - if (updateColor) { - if (ctx.shouldUpdate) await ctx.update('Computing trace colors'); - createColors(StructureElementIterator.fromGroup(currentGroup), newProps.colorTheme, renderObject.values) - } - - updateMeshValues(renderObject.values, newProps) - updateRenderableState(renderObject.state, newProps) - - currentProps = newProps - return true - }, - getLoci(pickingId: PickingId) { - return getElementLoci(renderObject.id, currentGroup, pickingId) - }, - mark(loci: Loci, action: MarkerAction) { - markElement(renderObject.values.tMarker, currentGroup, loci, action) - }, - destroy() { - // TODO - } - } -} + return UnitsMeshVisual<PolymerGapProps>({ + defaultProps: DefaultPolymerGapProps, + createMesh: createPolymerGapCylinderMesh, + createLocationIterator: StructureElementIterator.fromGroup, + getLoci: getElementLoci, + mark: markElement + }) +} \ No newline at end of file diff --git a/src/mol-geo/representation/structure/visual/polymer-trace-mesh.ts b/src/mol-geo/representation/structure/visual/polymer-trace-mesh.ts index 472f4366e..91b25ffe0 100644 --- a/src/mol-geo/representation/structure/visual/polymer-trace-mesh.ts +++ b/src/mol-geo/representation/structure/visual/polymer-trace-mesh.ts @@ -4,30 +4,20 @@ * @author Alexander Rose <alexander.rose@weirdbyte.de> */ -import { ValueCell } from 'mol-util/value-cell' - -import { MeshRenderObject } from 'mol-gl/render-object' -import { Unit, StructureElement } from 'mol-model/structure'; -import { DefaultStructureProps, UnitsVisual } from '..'; +import { Unit } from 'mol-model/structure'; +import { UnitsVisual } from '..'; import { RuntimeContext } from 'mol-task' -import { createColors, createUnitsMeshRenderObject } from './util/common'; -import { markElement } from './util/element'; -import { deepEqual } from 'mol-util'; +import { markElement, getElementLoci } from './util/element'; import { Mesh } from '../../../shape/mesh'; -import { PickingId } from '../../../util/picking'; -import { OrderedSet } from 'mol-data/int'; -import { MarkerAction } from '../../../util/marker-data'; -import { Loci, EmptyLoci } from 'mol-model/loci'; -import { SizeTheme } from '../../../theme'; -import { updateMeshValues, updateRenderableState, DefaultMeshProps } from '../../util'; import { MeshBuilder } from '../../../shape/mesh-builder'; import { getPolymerElementCount, PolymerTraceIterator, createCurveSegmentState, interpolateCurveSegment } from './util/polymer'; import { SecondaryStructureType, MoleculeType } from 'mol-model/structure/model/types'; import { StructureElementIterator } from './util/location-iterator'; +import { UnitsMeshVisual, DefaultUnitsMeshProps } from '../units-visual'; // TODO handle polymer ends properly -async function createPolymerTraceMesh(ctx: RuntimeContext, unit: Unit, mesh?: Mesh) { +async function createPolymerTraceMesh(ctx: RuntimeContext, unit: Unit, props: {}, mesh?: Mesh) { const polymerElementCount = getPolymerElementCount(unit) console.log('polymerElementCount trace', polymerElementCount) if (!polymerElementCount) return Mesh.createEmpty(mesh) @@ -80,79 +70,16 @@ async function createPolymerTraceMesh(ctx: RuntimeContext, unit: Unit, mesh?: Me } export const DefaultPolymerTraceProps = { - ...DefaultMeshProps, - ...DefaultStructureProps, - sizeTheme: { name: 'physical', factor: 1 } as SizeTheme, - detail: 0, - unitKinds: [ Unit.Kind.Atomic, Unit.Kind.Spheres ] as Unit.Kind[] + ...DefaultUnitsMeshProps } -export type PolymerTraceProps = Partial<typeof DefaultPolymerTraceProps> +export type PolymerTraceProps = typeof DefaultPolymerTraceProps export function PolymerTraceVisual(): UnitsVisual<PolymerTraceProps> { - let renderObject: MeshRenderObject - let currentProps: typeof DefaultPolymerTraceProps - let mesh: Mesh - let currentGroup: Unit.SymmetryGroup - - return { - get renderObject () { return renderObject }, - async create(ctx: RuntimeContext, group: Unit.SymmetryGroup, props: PolymerTraceProps = {}) { - currentProps = Object.assign({}, DefaultPolymerTraceProps, props) - currentGroup = group - - const { unitKinds } = { ...DefaultPolymerTraceProps, ...props } - const unit = group.units[0] - - mesh = unitKinds.includes(unit.kind) - ? await createPolymerTraceMesh(ctx, unit, mesh) - : Mesh.createEmpty(mesh) - - const locationIt = StructureElementIterator.fromGroup(group) - renderObject = createUnitsMeshRenderObject(group, mesh, locationIt, currentProps) - }, - async update(ctx: RuntimeContext, props: PolymerTraceProps) { - const newProps = Object.assign({}, currentProps, props) - - if (!renderObject) return false - - let updateColor = false - - if (newProps.detail !== currentProps.detail) { - const unit = currentGroup.units[0] - mesh = await createPolymerTraceMesh(ctx, unit, mesh) - ValueCell.update(renderObject.values.drawCount, mesh.triangleCount * 3) - updateColor = true - } - - if (!deepEqual(newProps.colorTheme, currentProps.colorTheme)) { - updateColor = true - } - - if (updateColor) { - if (ctx.shouldUpdate) await ctx.update('Computing trace colors'); - createColors(StructureElementIterator.fromGroup(currentGroup), newProps.colorTheme, renderObject.values) - } - - updateMeshValues(renderObject.values, newProps) - updateRenderableState(renderObject.state, newProps) - - currentProps = newProps - return true - }, - getLoci(pickingId: PickingId) { - const { objectId, instanceId, elementId } = pickingId - if (renderObject.id === objectId) { - const unit = currentGroup.units[instanceId] - const indices = OrderedSet.ofSingleton(elementId as StructureElement.UnitIndex); - return StructureElement.Loci([{ unit, indices }]) - } - return EmptyLoci - }, - mark(loci: Loci, action: MarkerAction) { - markElement(renderObject.values.tMarker, currentGroup, loci, action) - }, - destroy() { - // TODO - } - } -} + return UnitsMeshVisual<PolymerTraceProps>({ + defaultProps: DefaultPolymerTraceProps, + createMesh: createPolymerTraceMesh, + createLocationIterator: StructureElementIterator.fromGroup, + getLoci: getElementLoci, + mark: markElement + }) +} \ No newline at end of file diff --git a/src/mol-geo/representation/structure/visual/util/common.ts b/src/mol-geo/representation/structure/visual/util/common.ts index 25fd7d104..e07b033c5 100644 --- a/src/mol-geo/representation/structure/visual/util/common.ts +++ b/src/mol-geo/representation/structure/visual/util/common.ts @@ -86,7 +86,7 @@ function _createMeshValues(transforms: ValueCell<Float32Array>, mesh: Mesh, loca } } -export function createStructureMeshValues(structure: Structure, mesh: Mesh, locationIt: LocationIterator, props: StructureMeshProps): MeshValues { +export function createComplexMeshValues(structure: Structure, mesh: Mesh, locationIt: LocationIterator, props: StructureMeshProps): MeshValues { const transforms = createIdentityTransform() return _createMeshValues(transforms, mesh, locationIt, props) } @@ -96,8 +96,8 @@ export function createUnitsMeshValues(group: Unit.SymmetryGroup, mesh: Mesh, loc return _createMeshValues(transforms, mesh, locationIt, props) } -export function createStructureMeshRenderObject(structure: Structure, mesh: Mesh, locationIt: LocationIterator, props: StructureMeshProps) { - const values = createStructureMeshValues(structure, mesh, locationIt, props) +export function createComplexMeshRenderObject(structure: Structure, mesh: Mesh, locationIt: LocationIterator, props: StructureMeshProps) { + const values = createComplexMeshValues(structure, mesh, locationIt, props) const state = createRenderableState(props) return createMeshRenderObject(values, state) } @@ -106,4 +106,9 @@ export function createUnitsMeshRenderObject(group: Unit.SymmetryGroup, mesh: Mes const values = createUnitsMeshValues(group, mesh, locationIt, props) const state = createRenderableState(props) return createMeshRenderObject(values, state) +} + +export function updateComplexMeshRenderObject(structure: Structure, mesh: Mesh, locationIt: LocationIterator, props: StructureMeshProps): MeshValues { + const transforms = createIdentityTransform() + return _createMeshValues(transforms, mesh, locationIt, props) } \ No newline at end of file diff --git a/src/mol-geo/representation/structure/visual/util/element.ts b/src/mol-geo/representation/structure/visual/util/element.ts index 885b96aec..b23bc8010 100644 --- a/src/mol-geo/representation/structure/visual/util/element.ts +++ b/src/mol-geo/representation/structure/visual/util/element.ts @@ -12,9 +12,8 @@ import { sphereVertexCount } from '../../../../primitive/sphere'; import { Mesh } from '../../../../shape/mesh'; import { MeshBuilder } from '../../../../shape/mesh-builder'; import { ValueCell, defaults } from 'mol-util'; -import { TextureImage } from 'mol-gl/renderable/util'; import { Loci, isEveryLoci, EmptyLoci } from 'mol-model/loci'; -import { MarkerAction, applyMarkerAction } from '../../../../util/marker-data'; +import { MarkerAction, applyMarkerAction, MarkerData } from '../../../../util/marker-data'; import { Interval, OrderedSet } from 'mol-data/int'; import { getPhysicalRadius } from '../../../../theme/structure/size/physical'; import { PickingId } from '../../../../util/picking'; @@ -30,8 +29,16 @@ export function getElementRadius(unit: Unit, props: SizeTheme): StructureElement } } -export async function createElementSphereMesh(ctx: RuntimeContext, unit: Unit, radius: StructureElement.Property<number>, detail: number, mesh?: Mesh) { +export interface ElementSphereMeshProps { + sizeTheme: SizeTheme, + detail: number, +} + +export async function createElementSphereMesh(ctx: RuntimeContext, unit: Unit, props: ElementSphereMeshProps, mesh?: Mesh) { + const { detail, sizeTheme } = props + const { elements } = unit; + const radius = getElementRadius(unit, sizeTheme) const elementCount = elements.length; const vertexCount = elementCount * sphereVertexCount(detail) const meshBuilder = MeshBuilder.create(vertexCount, vertexCount / 2, mesh) @@ -56,10 +63,13 @@ export async function createElementSphereMesh(ctx: RuntimeContext, unit: Unit, r return meshBuilder.getMesh() } -export function markElement(tMarker: ValueCell<TextureImage>, group: Unit.SymmetryGroup, loci: Loci, action: MarkerAction) { - let changed = false +export function markElement(loci: Loci, action: MarkerAction, group: Unit.SymmetryGroup, values: MarkerData) { + const tMarker = values.tMarker + const elementCount = group.elements.length const instanceCount = group.units.length + + let changed = false const array = tMarker.ref.value.array if (isEveryLoci(loci)) { applyMarkerAction(array, 0, elementCount * instanceCount, action) @@ -92,7 +102,7 @@ export function markElement(tMarker: ValueCell<TextureImage>, group: Unit.Symmet } } -export function getElementLoci(id: number, group: Unit.SymmetryGroup, pickingId: PickingId) { +export function getElementLoci(pickingId: PickingId, group: Unit.SymmetryGroup, id: number) { const { objectId, instanceId, elementId } = pickingId if (id === objectId) { const unit = group.units[instanceId] diff --git a/src/mol-geo/representation/util.ts b/src/mol-geo/representation/util.ts index c76ad36b1..13d34ebec 100644 --- a/src/mol-geo/representation/util.ts +++ b/src/mol-geo/representation/util.ts @@ -18,7 +18,7 @@ export const DefaultBaseProps = { useFog: true, quality: 'auto' as VisualQuality } -export type BaseProps = Partial<typeof DefaultBaseProps> +export type BaseProps = typeof DefaultBaseProps export const DefaultMeshProps = { ...DefaultBaseProps, @@ -26,7 +26,7 @@ export const DefaultMeshProps = { flipSided: false, flatShaded: false, } -export type MeshProps = Partial<typeof DefaultMeshProps> +export type MeshProps = typeof DefaultMeshProps type Counts = { drawCount: number, elementCount: number, instanceCount: number } diff --git a/src/mol-geo/representation/volume/index.ts b/src/mol-geo/representation/volume/index.ts index c1f0706af..75555e2ca 100644 --- a/src/mol-geo/representation/volume/index.ts +++ b/src/mol-geo/representation/volume/index.ts @@ -11,18 +11,24 @@ import { VolumeData } from 'mol-model/volume'; import { PickingId } from '../../util/picking'; import { Loci, EmptyLoci } from 'mol-model/loci'; import { MarkerAction } from '../../util/marker-data'; +import { DefaultBaseProps } from '../util'; export interface VolumeVisual<P extends RepresentationProps = {}> extends Visual<VolumeData, P> { } export interface VolumeRepresentation<P extends RepresentationProps = {}> extends Representation<VolumeData, P> { } -export function VolumeRepresentation<P>(visualCtor: (volumeData: VolumeData) => VolumeVisual<P>): VolumeRepresentation<P> { +export const DefaultVolumeProps = { + ...DefaultBaseProps +} +export type VolumeProps = typeof DefaultVolumeProps + +export function VolumeRepresentation<P extends VolumeProps>(visualCtor: (volumeData: VolumeData) => VolumeVisual<P>): VolumeRepresentation<P> { const renderObjects: RenderObject[] = [] let _volumeData: VolumeData let _props: P - function create(volumeData: VolumeData, props: P = {} as P) { - _props = props + function create(volumeData: VolumeData, props: Partial<P> = {}) { + _props = Object.assign({}, DefaultVolumeProps, _props, props) return Task.create('VolumeRepresentation.create', async ctx => { _volumeData = volumeData const visual = visualCtor(_volumeData) @@ -31,7 +37,7 @@ export function VolumeRepresentation<P>(visualCtor: (volumeData: VolumeData) => }); } - function update(props: P) { + function update(props: Partial<P>) { return Task.create('VolumeRepresentation.update', async ctx => {}) } diff --git a/src/mol-model/structure/structure/unit/pair-restraints/data.ts b/src/mol-model/structure/structure/unit/pair-restraints/data.ts index 0fdd3ce75..7b0d01e86 100644 --- a/src/mol-model/structure/structure/unit/pair-restraints/data.ts +++ b/src/mol-model/structure/structure/unit/pair-restraints/data.ts @@ -5,6 +5,7 @@ */ import Unit from '../../unit'; +import { StructureElement } from '../../../structure'; const emptyArray: number[] = [] @@ -13,13 +14,13 @@ class CrossLinkRestraints { private readonly pairKeyIndices: Map<string, number[]> /** Indices into this.pairs */ - getPairIndices(indexA: number, unitA: Unit, indexB: number, unitB: Unit): ReadonlyArray<number> { + getPairIndices(indexA: StructureElement.UnitIndex, unitA: Unit, indexB: StructureElement.UnitIndex, unitB: Unit): ReadonlyArray<number> { const key = CrossLinkRestraints.getPairKey(indexA, unitA, indexB, unitB) const indices = this.pairKeyIndices.get(key) return indices !== undefined ? indices : emptyArray } - getPairs(indexA: number, unitA: Unit, indexB: number, unitB: Unit): CrossLinkRestraints.Pair[] | undefined { + getPairs(indexA: StructureElement.UnitIndex, unitA: Unit, indexB: StructureElement.UnitIndex, unitB: Unit): CrossLinkRestraints.Pair[] | undefined { const indices = this.getPairIndices(indexA, unitA, indexB, unitB) return indices.length ? indices.map(idx => this.pairs[idx]) : undefined } @@ -42,8 +43,8 @@ namespace CrossLinkRestraints { export interface Pair { readonly unitA: Unit, readonly unitB: Unit, - readonly indexA: number, - readonly indexB: number, + readonly indexA: StructureElement.UnitIndex, + readonly indexB: StructureElement.UnitIndex, readonly restraintType: 'harmonic' | 'upper bound' | 'lower bound', readonly distanceThreshold: number, @@ -52,7 +53,7 @@ namespace CrossLinkRestraints { readonly sigma2: number, } - export function getPairKey(indexA: number, unitA: Unit, indexB: number, unitB: Unit) { + export function getPairKey(indexA: StructureElement.UnitIndex, unitA: Unit, indexB: StructureElement.UnitIndex, unitB: Unit) { return `${indexA}|${unitA.id}|${indexB}|${unitB.id}` } } diff --git a/src/mol-model/structure/structure/unit/pair-restraints/extract-cross-links.ts b/src/mol-model/structure/structure/unit/pair-restraints/extract-cross-links.ts index a69307757..cfe6aaa23 100644 --- a/src/mol-model/structure/structure/unit/pair-restraints/extract-cross-links.ts +++ b/src/mol-model/structure/structure/unit/pair-restraints/extract-cross-links.ts @@ -8,6 +8,7 @@ import Unit from '../../unit'; import Structure from '../../structure'; import { IHMCrossLinkRestraint } from '../../../model/formats/mmcif/pair-restraint'; import { CrossLinkRestraints } from './data'; +import { StructureElement } from '../../../structure'; function _addRestraints(map: Map<number, number>, unit: Unit, restraints: IHMCrossLinkRestraint) { const { elements } = unit; @@ -27,8 +28,8 @@ function extractInter(pairs: CrossLinkRestraints.Pair[], unitA: Unit, unitB: Uni const restraints = IHMCrossLinkRestraint.fromModel(unitA.model) if (!restraints) return - const rA = new Map<number, number>(); - const rB = new Map<number, number>(); + const rA = new Map<number, StructureElement.UnitIndex>(); + const rB = new Map<number, StructureElement.UnitIndex>(); _addRestraints(rA, unitA, restraints) _addRestraints(rB, unitB, restraints) @@ -53,14 +54,14 @@ function extractIntra(pairs: CrossLinkRestraints.Pair[], unit: Unit) { const elementCount = elements.length; const kind = unit.kind - const r = new Map<number, number[]>(); + const r = new Map<number, StructureElement.UnitIndex[]>(); for (let i = 0; i < elementCount; i++) { const e = elements[i]; restraints.getIndicesByElement(e, kind).forEach(ri => { const il = r.get(ri) - if (il) il.push(i) - else r.set(ri, [i]) + if (il) il.push(i as StructureElement.UnitIndex) + else r.set(ri, [i as StructureElement.UnitIndex]) }) } @@ -74,7 +75,7 @@ function extractIntra(pairs: CrossLinkRestraints.Pair[], unit: Unit) { }) } -function createCrossLinkRestraint(unitA: Unit, indexA: number, unitB: Unit, indexB: number, restraints: IHMCrossLinkRestraint, row: number): CrossLinkRestraints.Pair { +function createCrossLinkRestraint(unitA: Unit, indexA: StructureElement.UnitIndex, unitB: Unit, indexB: StructureElement.UnitIndex, restraints: IHMCrossLinkRestraint, row: number): CrossLinkRestraints.Pair { return { unitA, indexA, unitB, indexB, diff --git a/src/mol-view/stage.ts b/src/mol-view/stage.ts index 06c561e74..f490b055a 100644 --- a/src/mol-view/stage.ts +++ b/src/mol-view/stage.ts @@ -17,14 +17,14 @@ import { DistanceRestraintProps } from 'mol-geo/representation/structure/represe import { BackboneProps } from 'mol-geo/representation/structure/representation/backbone'; // import { Queries as Q, StructureProperties as SP, Query, Selection } from 'mol-model/structure'; -const spacefillProps: SpacefillProps = { +const spacefillProps: Partial<SpacefillProps> = { doubleSided: true, colorTheme: { name: 'chain-id' }, quality: 'auto', useFog: false } -const ballAndStickProps: BallAndStickProps = { +const ballAndStickProps: Partial<BallAndStickProps> = { doubleSided: true, colorTheme: { name: 'chain-id' }, sizeTheme: { name: 'uniform', value: 0.15 }, @@ -33,7 +33,7 @@ const ballAndStickProps: BallAndStickProps = { useFog: false } -const distanceRestraintProps: DistanceRestraintProps = { +const distanceRestraintProps: Partial<DistanceRestraintProps> = { doubleSided: true, colorTheme: { name: 'chain-id' }, linkRadius: 0.5, @@ -41,7 +41,7 @@ const distanceRestraintProps: DistanceRestraintProps = { useFog: false } -const backboneProps: BackboneProps = { +const backboneProps: Partial<BackboneProps> = { doubleSided: true, colorTheme: { name: 'chain-id' }, // colorTheme: { name: 'uniform', value: 0xFF0000 }, @@ -50,7 +50,7 @@ const backboneProps: BackboneProps = { alpha: 0.5 } -const cartoonProps: CartoonProps = { +const cartoonProps: Partial<CartoonProps> = { doubleSided: true, colorTheme: { name: 'chain-id' }, // colorTheme: { name: 'uniform', value: 0x2200CC }, @@ -58,7 +58,7 @@ const cartoonProps: CartoonProps = { useFog: false } -const carbohydrateProps: CartoonProps = { +const carbohydrateProps: Partial<CartoonProps> = { doubleSided: true, colorTheme: { name: 'carbohydrate-symbol' }, // colorTheme: { name: 'uniform', value: 0x2200CC }, diff --git a/src/mol-view/state/entity.ts b/src/mol-view/state/entity.ts index 22c94076f..60ba57af0 100644 --- a/src/mol-view/state/entity.ts +++ b/src/mol-view/state/entity.ts @@ -122,41 +122,41 @@ export namespace StructureEntity { export type SpacefillEntity = StateEntity<StructureRepresentation<SpacefillProps>, 'spacefill'> export namespace SpacefillEntity { export function ofRepr(ctx: StateContext, repr: StructureRepresentation<SpacefillProps>): SpacefillEntity { - return StateEntity.create(ctx, 'spacefill', repr ) + return StateEntity.create(ctx, 'spacefill', repr) } } export type BallAndStickEntity = StateEntity<StructureRepresentation<BallAndStickProps>, 'ballandstick'> export namespace BallAndStickEntity { export function ofRepr(ctx: StateContext, repr: StructureRepresentation<BallAndStickProps>): BallAndStickEntity { - return StateEntity.create(ctx, 'ballandstick', repr ) + return StateEntity.create(ctx, 'ballandstick', repr) } } export type DistanceRestraintEntity = StateEntity<StructureRepresentation<DistanceRestraintProps>, 'distancerestraint'> export namespace DistanceRestraintEntity { export function ofRepr(ctx: StateContext, repr: StructureRepresentation<DistanceRestraintProps>): DistanceRestraintEntity { - return StateEntity.create(ctx, 'distancerestraint', repr ) + return StateEntity.create(ctx, 'distancerestraint', repr) } } export type BackboneEntity = StateEntity<StructureRepresentation<BackboneProps>, 'backbone'> export namespace BackboneEntity { export function ofRepr(ctx: StateContext, repr: StructureRepresentation<BackboneProps>): BackboneEntity { - return StateEntity.create(ctx, 'backbone', repr ) + return StateEntity.create(ctx, 'backbone', repr) } } export type CartoonEntity = StateEntity<StructureRepresentation<CartoonProps>, 'cartoon'> export namespace CartoonEntity { export function ofRepr(ctx: StateContext, repr: StructureRepresentation<CartoonProps>): CartoonEntity { - return StateEntity.create(ctx, 'cartoon', repr ) + return StateEntity.create(ctx, 'cartoon', repr) } } export type CarbohydrateEntity = StateEntity<StructureRepresentation<CarbohydrateProps>, 'carbohydrate'> export namespace CarbohydrateEntity { export function ofRepr(ctx: StateContext, repr: StructureRepresentation<CarbohydrateProps>): CarbohydrateEntity { - return StateEntity.create(ctx, 'carbohydrate', repr ) + return StateEntity.create(ctx, 'carbohydrate', repr) } } \ No newline at end of file diff --git a/src/mol-view/state/transform.ts b/src/mol-view/state/transform.ts index b4381c8b3..bda97a320 100644 --- a/src/mol-view/state/transform.ts +++ b/src/mol-view/state/transform.ts @@ -95,9 +95,9 @@ export const StructureCenter: StructureCenter = StateTransform.create('structure return NullEntity }) -export type StructureToSpacefill = StateTransform<StructureEntity, SpacefillEntity, SpacefillProps> +export type StructureToSpacefill = StateTransform<StructureEntity, SpacefillEntity, Partial<SpacefillProps>> export const StructureToSpacefill: StructureToSpacefill = StateTransform.create('structure', 'spacefill', 'structure-to-spacefill', - async function (ctx: StateContext, structureEntity: StructureEntity, props: SpacefillProps = {}) { + async function (ctx: StateContext, structureEntity: StructureEntity, props: Partial<SpacefillProps> = {}) { const spacefillRepr = SpacefillRepresentation() await spacefillRepr.create(structureEntity.value, props).run(ctx.log) ctx.viewer.add(spacefillRepr) @@ -106,9 +106,9 @@ export const StructureToSpacefill: StructureToSpacefill = StateTransform.create( return SpacefillEntity.ofRepr(ctx, spacefillRepr) }) -export type StructureToBallAndStick = StateTransform<StructureEntity, BallAndStickEntity, BallAndStickProps> +export type StructureToBallAndStick = StateTransform<StructureEntity, BallAndStickEntity, Partial<BallAndStickProps>> export const StructureToBallAndStick: StructureToBallAndStick = StateTransform.create('structure', 'ballandstick', 'structure-to-ballandstick', - async function (ctx: StateContext, structureEntity: StructureEntity, props: BallAndStickProps = {}) { + async function (ctx: StateContext, structureEntity: StructureEntity, props: Partial<BallAndStickProps> = {}) { const ballAndStickRepr = BallAndStickRepresentation() await ballAndStickRepr.create(structureEntity.value, props).run(ctx.log) ctx.viewer.add(ballAndStickRepr) @@ -117,9 +117,9 @@ export const StructureToBallAndStick: StructureToBallAndStick = StateTransform.c return BallAndStickEntity.ofRepr(ctx, ballAndStickRepr) }) -export type StructureToDistanceRestraint = StateTransform<StructureEntity, DistanceRestraintEntity, DistanceRestraintProps> +export type StructureToDistanceRestraint = StateTransform<StructureEntity, DistanceRestraintEntity, Partial<DistanceRestraintProps>> export const StructureToDistanceRestraint: StructureToDistanceRestraint = StateTransform.create('structure', 'distancerestraint', 'structure-to-distancerestraint', - async function (ctx: StateContext, structureEntity: StructureEntity, props: DistanceRestraintProps = {}) { + async function (ctx: StateContext, structureEntity: StructureEntity, props: Partial<DistanceRestraintProps> = {}) { const distanceRestraintRepr = DistanceRestraintRepresentation() await distanceRestraintRepr.create(structureEntity.value, props).run(ctx.log) ctx.viewer.add(distanceRestraintRepr) @@ -128,9 +128,9 @@ export const StructureToDistanceRestraint: StructureToDistanceRestraint = StateT return DistanceRestraintEntity.ofRepr(ctx, distanceRestraintRepr) }) -export type StructureToBackbone = StateTransform<StructureEntity, BackboneEntity, BackboneProps> +export type StructureToBackbone = StateTransform<StructureEntity, BackboneEntity, Partial<BackboneProps>> export const StructureToBackbone: StructureToBackbone = StateTransform.create('structure', 'backbone', 'structure-to-backbone', - async function (ctx: StateContext, structureEntity: StructureEntity, props: BackboneProps = {}) { + async function (ctx: StateContext, structureEntity: StructureEntity, props: Partial<BackboneProps> = {}) { const backboneRepr = BackboneRepresentation() await backboneRepr.create(structureEntity.value, props).run(ctx.log) ctx.viewer.add(backboneRepr) @@ -139,9 +139,9 @@ export const StructureToBackbone: StructureToBackbone = StateTransform.create('s return BackboneEntity.ofRepr(ctx, backboneRepr) }) -export type StructureToCartoon = StateTransform<StructureEntity, CartoonEntity, CartoonProps> +export type StructureToCartoon = StateTransform<StructureEntity, CartoonEntity, Partial<CartoonProps>> export const StructureToCartoon: StructureToCartoon = StateTransform.create('structure', 'cartoon', 'structure-to-cartoon', - async function (ctx: StateContext, structureEntity: StructureEntity, props: CartoonProps = {}) { + async function (ctx: StateContext, structureEntity: StructureEntity, props: Partial<CartoonProps> = {}) { const cartoonRepr = CartoonRepresentation() await cartoonRepr.create(structureEntity.value, props).run(ctx.log) ctx.viewer.add(cartoonRepr) @@ -150,9 +150,9 @@ export const StructureToCartoon: StructureToCartoon = StateTransform.create('str return CartoonEntity.ofRepr(ctx, cartoonRepr) }) -export type StructureToCarbohydrate = StateTransform<StructureEntity, CarbohydrateEntity, CarbohydrateProps> +export type StructureToCarbohydrate = StateTransform<StructureEntity, CarbohydrateEntity, Partial<CarbohydrateProps>> export const StructureToCarbohydrate: StructureToCarbohydrate = StateTransform.create('structure', 'carbohydrate', 'structure-to-cartoon', - async function (ctx: StateContext, structureEntity: StructureEntity, props: CarbohydrateProps = {}) { + async function (ctx: StateContext, structureEntity: StructureEntity, props: Partial<CarbohydrateProps> = {}) { const carbohydrateRepr = CarbohydrateRepresentation() await carbohydrateRepr.create(structureEntity.value, props).run(ctx.log) ctx.viewer.add(carbohydrateRepr) @@ -161,9 +161,9 @@ export const StructureToCarbohydrate: StructureToCarbohydrate = StateTransform.c return CarbohydrateEntity.ofRepr(ctx, carbohydrateRepr) }) -export type SpacefillUpdate = StateTransform<SpacefillEntity, NullEntity, SpacefillProps> +export type SpacefillUpdate = StateTransform<SpacefillEntity, NullEntity, Partial<SpacefillProps>> export const SpacefillUpdate: SpacefillUpdate = StateTransform.create('spacefill', 'null', 'spacefill-update', - async function (ctx: StateContext, spacefillEntity: SpacefillEntity, props: SpacefillProps = {}) { + async function (ctx: StateContext, spacefillEntity: SpacefillEntity, props: Partial<SpacefillProps> = {}) { const spacefillRepr = spacefillEntity.value await spacefillRepr.update(props).run(ctx.log) ctx.viewer.add(spacefillRepr) @@ -172,9 +172,9 @@ export const SpacefillUpdate: SpacefillUpdate = StateTransform.create('spacefill return NullEntity }) -export type BallAndStickUpdate = StateTransform<BallAndStickEntity, NullEntity, BallAndStickProps> +export type BallAndStickUpdate = StateTransform<BallAndStickEntity, NullEntity, Partial<BallAndStickProps>> export const BallAndStickUpdate: BallAndStickUpdate = StateTransform.create('ballandstick', 'null', 'ballandstick-update', - async function (ctx: StateContext, ballAndStickEntity: BallAndStickEntity, props: BallAndStickProps = {}) { + async function (ctx: StateContext, ballAndStickEntity: BallAndStickEntity, props: Partial<BallAndStickProps> = {}) { const ballAndStickRepr = ballAndStickEntity.value await ballAndStickRepr.update(props).run(ctx.log) ctx.viewer.add(ballAndStickRepr) @@ -183,9 +183,9 @@ export const BallAndStickUpdate: BallAndStickUpdate = StateTransform.create('bal return NullEntity }) -export type DistanceRestraintUpdate = StateTransform<DistanceRestraintEntity, NullEntity, DistanceRestraintProps> +export type DistanceRestraintUpdate = StateTransform<DistanceRestraintEntity, NullEntity, Partial<DistanceRestraintProps>> export const DistanceRestraintUpdate: DistanceRestraintUpdate = StateTransform.create('distancerestraint', 'null', 'distancerestraint-update', - async function (ctx: StateContext, distanceRestraintEntity: DistanceRestraintEntity, props: DistanceRestraintProps = {}) { + async function (ctx: StateContext, distanceRestraintEntity: DistanceRestraintEntity, props: Partial<DistanceRestraintProps> = {}) { const distanceRestraintRepr = distanceRestraintEntity.value await distanceRestraintRepr.update(props).run(ctx.log) ctx.viewer.add(distanceRestraintRepr) @@ -194,9 +194,9 @@ export const DistanceRestraintUpdate: DistanceRestraintUpdate = StateTransform.c return NullEntity }) -export type BackboneUpdate = StateTransform<BackboneEntity, NullEntity, BackboneProps> +export type BackboneUpdate = StateTransform<BackboneEntity, NullEntity, Partial<BackboneProps>> export const BackboneUpdate: BackboneUpdate = StateTransform.create('backbone', 'null', 'backbone-update', - async function (ctx: StateContext, backboneEntity: BackboneEntity, props: BackboneProps = {}) { + async function (ctx: StateContext, backboneEntity: BackboneEntity, props: Partial<BackboneProps> = {}) { const backboneRepr = backboneEntity.value await backboneRepr.update(props).run(ctx.log) ctx.viewer.add(backboneRepr) @@ -205,9 +205,9 @@ export const BackboneUpdate: BackboneUpdate = StateTransform.create('backbone', return NullEntity }) -export type CartoonUpdate = StateTransform<CartoonEntity, NullEntity, CartoonProps> +export type CartoonUpdate = StateTransform<CartoonEntity, NullEntity, Partial<CartoonProps>> export const CartoonUpdate: CartoonUpdate = StateTransform.create('cartoon', 'null', 'cartoon-update', - async function (ctx: StateContext, cartoonEntity: CartoonEntity, props: CartoonProps = {}) { + async function (ctx: StateContext, cartoonEntity: CartoonEntity, props: Partial<CartoonProps> = {}) { const cartoonRepr = cartoonEntity.value await cartoonRepr.update(props).run(ctx.log) ctx.viewer.add(cartoonRepr) @@ -216,9 +216,9 @@ export const CartoonUpdate: CartoonUpdate = StateTransform.create('cartoon', 'nu return NullEntity }) -export type CarbohydrateUpdate = StateTransform<CarbohydrateEntity, NullEntity, CarbohydrateProps> +export type CarbohydrateUpdate = StateTransform<CarbohydrateEntity, NullEntity, Partial<CarbohydrateProps>> export const CarbohydrateUpdate: CarbohydrateUpdate = StateTransform.create('carbohydrate', 'null', 'carbohydrate-update', - async function (ctx: StateContext, carbohydrateEntity: CarbohydrateEntity, props: CarbohydrateProps = {}) { + async function (ctx: StateContext, carbohydrateEntity: CarbohydrateEntity, props: Partial<CarbohydrateProps> = {}) { const carbohydrateRepr = carbohydrateEntity.value await carbohydrateRepr.update(props).run(ctx.log) ctx.viewer.add(carbohydrateRepr) @@ -251,24 +251,24 @@ export const DataToModel: DataToModel = StateTransform.create('data', 'model', ' return MmcifToModel.apply(ctx, mmcifEntity) }) -export type ModelToSpacefill = StateTransform<ModelEntity, SpacefillEntity, SpacefillProps> +export type ModelToSpacefill = StateTransform<ModelEntity, SpacefillEntity, Partial<SpacefillProps>> export const ModelToSpacefill: ModelToSpacefill = StateTransform.create('model', 'spacefill', 'model-to-spacefill', - async function (ctx: StateContext, modelEntity: ModelEntity, props: SpacefillProps = {}) { + async function (ctx: StateContext, modelEntity: ModelEntity, props: Partial<SpacefillProps> = {}) { const structureEntity = await ModelToStructure.apply(ctx, modelEntity) // StructureToBond.apply(ctx, structureEntity, props) return StructureToSpacefill.apply(ctx, structureEntity, props) }) -export type MmcifUrlToSpacefill = StateTransform<UrlEntity, SpacefillEntity, SpacefillProps> +export type MmcifUrlToSpacefill = StateTransform<UrlEntity, SpacefillEntity, Partial<SpacefillProps>> export const MmcifUrlToSpacefill: MmcifUrlToSpacefill = StateTransform.create('url', 'spacefill', 'url-to-spacefill', - async function (ctx: StateContext, urlEntity: UrlEntity, props: SpacefillProps = {}) { + async function (ctx: StateContext, urlEntity: UrlEntity, props: Partial<SpacefillProps> = {}) { const modelEntity = await MmcifUrlToModel.apply(ctx, urlEntity) return ModelToSpacefill.apply(ctx, modelEntity, props) }) -export type MmcifFileToSpacefill = StateTransform<FileEntity, SpacefillEntity, SpacefillProps> +export type MmcifFileToSpacefill = StateTransform<FileEntity, SpacefillEntity, Partial<SpacefillProps>> export const MmcifFileToSpacefill: MmcifFileToSpacefill = StateTransform.create('file', 'spacefill', 'file-to-spacefill', - async function (ctx: StateContext, fileEntity: FileEntity, props: SpacefillProps = {}) { + async function (ctx: StateContext, fileEntity: FileEntity, props: Partial<SpacefillProps> = {}) { const modelEntity = await MmcifFileToModel.apply(ctx, fileEntity) return ModelToSpacefill.apply(ctx, modelEntity, props) }) \ No newline at end of file -- GitLab