diff --git a/src/mol-geo/representation/structure/ball-and-stick.ts b/src/mol-geo/representation/structure/ball-and-stick.ts index de1004d9b138192261155c16ef6d5a67a0b2390f..2883582a5081172bcde9672c71a6c111af4eb1ec 100644 --- a/src/mol-geo/representation/structure/ball-and-stick.ts +++ b/src/mol-geo/representation/structure/ball-and-stick.ts @@ -4,7 +4,7 @@ * @author Alexander Rose <alexander.rose@weirdbyte.de> */ -import { StructureRepresentation } from '.'; +import { StructureRepresentation, StructureUnitsRepresentation } from '.'; import { ElementSphereVisual, DefaultElementSphereProps } from './visual/element-sphere'; import { IntraUnitLinkVisual, DefaultIntraUnitLinkProps } from './visual/intra-unit-link-cylinder'; import { PickingId } from '../../util/picking'; @@ -25,46 +25,56 @@ export const DefaultBallAndStickProps = { export type BallAndStickProps = Partial<typeof DefaultBallAndStickProps> export function BallAndStickRepresentation(): StructureRepresentation<BallAndStickProps> { - const elmementRepr = StructureRepresentation(ElementSphereVisual) - const linkRepr = StructureRepresentation(IntraUnitLinkVisual, InterUnitLinkVisual) + const elmementRepr = StructureUnitsRepresentation(ElementSphereVisual) + const intraLinkRepr = StructureUnitsRepresentation(IntraUnitLinkVisual) + const interLinkRepr = StructureRepresentation(InterUnitLinkVisual) return { get renderObjects() { - return [ ...elmementRepr.renderObjects, ...linkRepr.renderObjects ] + return [ ...elmementRepr.renderObjects, ...intraLinkRepr.renderObjects, ...interLinkRepr.renderObjects ] }, get props() { - return { ...elmementRepr.props, ...linkRepr.props } + return { ...elmementRepr.props, ...intraLinkRepr.props, ...interLinkRepr.props } }, create: (structure: Structure, props: BallAndStickProps = {} as BallAndStickProps) => { const p = Object.assign({}, DefaultBallAndStickProps, props) - return Task.create('Creating BallAndStickRepresentation', async ctx => { + return Task.create('DistanceRestraintRepresentation', async ctx => { await elmementRepr.create(structure, p).runInContext(ctx) - await linkRepr.create(structure, p).runInContext(ctx) + await intraLinkRepr.create(structure, p).runInContext(ctx) + await interLinkRepr.create(structure, p).runInContext(ctx) }) }, update: (props: BallAndStickProps) => { const p = Object.assign({}, props) return Task.create('Updating BallAndStickRepresentation', async ctx => { await elmementRepr.update(p).runInContext(ctx) - await linkRepr.update(p).runInContext(ctx) + await intraLinkRepr.update(p).runInContext(ctx) + await interLinkRepr.update(p).runInContext(ctx) }) }, getLoci: (pickingId: PickingId) => { const sphereLoci = elmementRepr.getLoci(pickingId) - const intraLinkLoci = linkRepr.getLoci(pickingId) + const intraLinkLoci = intraLinkRepr.getLoci(pickingId) + const interLinkLoci = interLinkRepr.getLoci(pickingId) if (isEmptyLoci(sphereLoci)) { - return intraLinkLoci + if (isEmptyLoci(intraLinkLoci)) { + return interLinkLoci + } else { + return intraLinkLoci + } } else { return sphereLoci } }, mark: (loci: Loci, action: MarkerAction) => { elmementRepr.mark(loci, action) - linkRepr.mark(loci, action) + intraLinkRepr.mark(loci, action) + interLinkRepr.mark(loci, action) }, destroy() { elmementRepr.destroy() - linkRepr.destroy() + intraLinkRepr.destroy() + interLinkRepr.destroy() } } } \ 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 25d49da0194698dea4ced08ea0a0725ac887a06a..d0bc2eb18a8188c3c9f739580d9e2266a53484a4 100644 --- a/src/mol-geo/representation/structure/index.ts +++ b/src/mol-geo/representation/structure/index.ts @@ -27,9 +27,74 @@ export const DefaultStructureProps = { } export type StructureProps = Partial<typeof DefaultStructureProps> -export function StructureRepresentation<P extends StructureProps>(unitsVisualCtor: () => UnitsVisual<P>, structureVisualCtor?: () => StructureVisual<P>): StructureRepresentation<P> { - let unitsVisuals = new Map<number, { group: Unit.SymmetryGroup, visual: UnitsVisual<P> }>() - let structureVisual: StructureVisual<P> | undefined +export function StructureRepresentation<P extends StructureProps>(visualCtor: () => StructureVisual<P>): StructureRepresentation<P> { + let visual: StructureVisual<P> + + let _props: Required<P> + let _structure: Structure + + function create(structure: Structure, props: P = {} as P) { + _props = Object.assign({}, DefaultStructureProps, _props, props, getQualityProps(props, structure)) + + return Task.create('Creating StructureRepresentation', async ctx => { + if (!_structure) { + visual = visualCtor() + await visual.create(ctx, structure, _props) + } else { + if (_structure.hashCode === structure.hashCode) { + await update(_props) + } else { + if (!await visual.update(ctx, _props)) { + await visual.create(ctx, _structure, _props) + } + } + } + _structure = structure + }); + } + + function update(props: P) { + return Task.create('Updating StructureRepresentation', async ctx => { + _props = Object.assign({}, DefaultStructureProps, _props, props, getQualityProps(props, _structure)) + + if (!await visual.update(ctx, _props)) { + await visual.create(ctx, _structure, _props) + } + }) + } + + function getLoci(pickingId: PickingId) { + let loci: Loci = EmptyLoci + const _loci = visual.getLoci(pickingId) + if (!isEmptyLoci(_loci)) loci = _loci + return loci + } + + function mark(loci: Loci, action: MarkerAction) { + visual.mark(loci, action) + } + + function destroy() { + visual.destroy() + } + + return { + get renderObjects() { + return visual.renderObjects + }, + get props() { + return _props + }, + create, + update, + getLoci, + mark, + destroy + } +} + +export function StructureUnitsRepresentation<P extends StructureProps>(visualCtor: () => UnitsVisual<P>): StructureRepresentation<P> { + let visuals = new Map<number, { group: Unit.SymmetryGroup, visual: UnitsVisual<P> }>() let _props: Required<P> let _structure: Structure @@ -43,14 +108,9 @@ export function StructureRepresentation<P extends StructureProps>(unitsVisualCto _groups = StructureSymmetry.getTransformGroups(structure); for (let i = 0; i < _groups.length; i++) { const group = _groups[i]; - const visual = unitsVisualCtor() + const visual = visualCtor() await visual.create(ctx, group, _props) - unitsVisuals.set(group.hashCode, { visual, group }) - } - - if (structureVisualCtor) { - structureVisual = structureVisualCtor() - await structureVisual.create(ctx, structure, _props) + visuals.set(group.hashCode, { visual, group }) } } else { if (_structure.hashCode === structure.hashCode) { @@ -58,8 +118,8 @@ export function StructureRepresentation<P extends StructureProps>(unitsVisualCto } else { _groups = StructureSymmetry.getTransformGroups(structure); const newGroups: Unit.SymmetryGroup[] = [] - const oldUnitsVisuals = unitsVisuals - unitsVisuals = new Map() + const oldUnitsVisuals = visuals + visuals = new Map() for (let i = 0; i < _groups.length; i++) { const group = _groups[i]; const visualGroup = oldUnitsVisuals.get(group.hashCode) @@ -71,9 +131,9 @@ export function StructureRepresentation<P extends StructureProps>(unitsVisualCto oldUnitsVisuals.delete(group.hashCode) } else { newGroups.push(group) - const visual = unitsVisualCtor() + const visual = visualCtor() await visual.create(ctx, group, _props) - unitsVisuals.set(group.hashCode, { visual, group }) + visuals.set(group.hashCode, { visual, group }) } } @@ -81,17 +141,11 @@ export function StructureRepresentation<P extends StructureProps>(unitsVisualCto const unusedVisuals: UnitsVisual<P>[] = [] oldUnitsVisuals.forEach(({ visual }) => unusedVisuals.push(visual)) newGroups.forEach(async group => { - const visual = unusedVisuals.pop() || unitsVisualCtor() + const visual = unusedVisuals.pop() || visualCtor() await visual.create(ctx, group, _props) - unitsVisuals.set(group.hashCode, { visual, group }) + visuals.set(group.hashCode, { visual, group }) }) unusedVisuals.forEach(visual => visual.destroy()) - - if (structureVisual) { - if (!await structureVisual.update(ctx, _props)) { - await structureVisual.create(ctx, _structure, _props) - } - } } } _structure = structure @@ -100,57 +154,38 @@ export function StructureRepresentation<P extends StructureProps>(unitsVisualCto function update(props: P) { return Task.create('Updating StructureRepresentation', async ctx => { - console.log(getQualityProps(props, _structure)) _props = Object.assign({}, DefaultStructureProps, _props, props, getQualityProps(props, _structure)) - console.log('update struct', (_props as any).detail, (_props as any).radialSegments) - - unitsVisuals.forEach(async ({ visual, group }) => { + visuals.forEach(async ({ visual, group }) => { if (!await visual.update(ctx, _props)) { await visual.create(ctx, group, _props) } }) - - if (structureVisual) { - if (!await structureVisual.update(ctx, _props)) { - await structureVisual.create(ctx, _structure, _props) - } - } }) } function getLoci(pickingId: PickingId) { let loci: Loci = EmptyLoci - unitsVisuals.forEach(({ visual }) => { + visuals.forEach(({ visual }) => { const _loci = visual.getLoci(pickingId) if (!isEmptyLoci(_loci)) loci = _loci }) - if (structureVisual) { - const _loci = structureVisual.getLoci(pickingId) - if (!isEmptyLoci(_loci)) loci = _loci - } return loci } function mark(loci: Loci, action: MarkerAction) { - unitsVisuals.forEach(({ visual }) => visual.mark(loci, action)) - if (structureVisual) structureVisual.mark(loci, action) + visuals.forEach(({ visual }) => visual.mark(loci, action)) } function destroy() { - unitsVisuals.forEach(({ visual }) => visual.destroy()) - unitsVisuals.clear() - if (structureVisual) { - structureVisual.destroy() - structureVisual = undefined - } + visuals.forEach(({ visual }) => visual.destroy()) + visuals.clear() } return { get renderObjects() { const renderObjects: RenderObject[] = [] - unitsVisuals.forEach(({ visual }) => renderObjects.push(...visual.renderObjects)) - if (structureVisual) renderObjects.push(...structureVisual.renderObjects) + visuals.forEach(({ visual }) => renderObjects.push(...visual.renderObjects)) return renderObjects }, get props() { diff --git a/src/mol-geo/representation/structure/spacefill.ts b/src/mol-geo/representation/structure/spacefill.ts index 7847fd9f65c63555a72bd351c4aced7f23a10ad7..37ab7eba9d60c3d8167f714487c3bca3d2c72c7a 100644 --- a/src/mol-geo/representation/structure/spacefill.ts +++ b/src/mol-geo/representation/structure/spacefill.ts @@ -4,7 +4,7 @@ * @author Alexander Rose <alexander.rose@weirdbyte.de> */ -import { StructureRepresentation } from '.'; +import { StructureUnitsRepresentation } from '.'; import { ElementSphereVisual, DefaultElementSphereProps } from './visual/element-sphere'; export const DefaultSpacefillProps = { @@ -13,5 +13,5 @@ export const DefaultSpacefillProps = { export type SpacefillProps = Partial<typeof DefaultSpacefillProps> export function SpacefillRepresentation() { - return StructureRepresentation(ElementSphereVisual) + return StructureUnitsRepresentation(ElementSphereVisual) } \ 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 1ee582192a85e264e6722e62de9a2d4d8fbe7bcd..1195e0ab787fde13c298aab34fec8b93be76781b 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 @@ -77,8 +77,7 @@ export function InterUnitLinkVisual(): StructureVisual<InterUnitLinkProps> { const transforms = createIdentityTransform() if (ctx.shouldUpdate) await ctx.update('Computing link colors'); - const color = createUniformColor({ value: 0x999911 }) - // const color = chainIdLinkColorData({ group, elementCount }) + const color = createUniformColor({ value: 0x999911 }) // TODO if (ctx.shouldUpdate) await ctx.update('Computing link marks'); const marker = createMarkers(instanceCount * elementCount) 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 f6633c75dccdb4873b5e5ad2c0c031dd9fed4f63..c747d572699659886f9fa2c05c128eb75cef75a1 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 @@ -94,8 +94,7 @@ export function IntraUnitLinkVisual(): UnitsVisual<IntraUnitLinkProps> { const transforms = createTransforms(group) if (ctx.shouldUpdate) await ctx.update('Computing link colors'); - // const color = createUniformColor({ value: 0xFF0000 }) - const color = chainIdLinkColorData({ group, elementCount }) + const color = chainIdLinkColorData({ group, elementCount }) // TODO if (ctx.shouldUpdate) await ctx.update('Computing link marks'); const marker = createMarkers(instanceCount * elementCount) @@ -118,8 +117,10 @@ export function IntraUnitLinkVisual(): UnitsVisual<IntraUnitLinkProps> { async update(ctx: RuntimeContext, props: IntraUnitLinkProps) { const newProps = Object.assign({}, currentProps, props) - if (!cylinders || currentProps.radialSegments !== newProps.radialSegments) return false - // TODO + if (!cylinders) return false + + // TODO create in-place + if (currentProps.radialSegments !== newProps.radialSegments) return false updateMeshValues(cylinders.values, newProps) updateRenderableState(cylinders.state, newProps)