diff --git a/src/mol-geo/representation/structure/units-representation.ts b/src/mol-geo/representation/structure/units-representation.ts index 766845896c9f491b0a225218409ab9512bdf9a8c..79a9c480645714079b51d38c571d7da268f82ced 100644 --- a/src/mol-geo/representation/structure/units-representation.ts +++ b/src/mol-geo/representation/structure/units-representation.ts @@ -34,6 +34,7 @@ export function UnitsRepresentation<P extends StructureProps>(label: string, vis if (!_structure && !structure) { throw new Error('missing structure') } else if (structure && !_structure) { + // console.log('initial structure') // First call with a structure, create visuals for each group. _groups = structure.unitSymmetryGroups; for (let i = 0; i < _groups.length; i++) { @@ -43,6 +44,7 @@ export function UnitsRepresentation<P extends StructureProps>(label: string, vis visuals.set(group.hashCode, { visual, group }) } } else if (structure && _structure.hashCode !== structure.hashCode) { + // console.log('_structure.hashCode !== structure.hashCode') // Tries to re-use existing visuals for the groups of the new structure. // Creates additional visuals if needed, destroys left-over visuals. _groups = structure.unitSymmetryGroups; @@ -77,6 +79,7 @@ export function UnitsRepresentation<P extends StructureProps>(label: string, vis // }) // unusedVisuals.forEach(visual => visual.destroy()) } else if (structure && _structure.hashCode === structure.hashCode) { + // console.log('_structure.hashCode === structure.hashCode') // Expects that for structures with the same hashCode, // the unitSymmetryGroups are the same as well. // Re-uses existing visuals for the groups of the new structure. @@ -92,6 +95,7 @@ export function UnitsRepresentation<P extends StructureProps>(label: string, vis } } } else { + // console.log('no new structure') // No new structure given, just update all visuals with new props. visuals.forEach(async ({ visual, group }) => { await visual.createOrUpdate(ctx, _props, { group, structure: _structure }) 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 66c2817fd01f326ee6dc36403768f27b0418a69c..f7d82a34a3de4967a425a480c6355dea118ee598 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 @@ -103,8 +103,8 @@ function markLink(loci: Loci, group: Unit.SymmetryGroup, apply: (interval: Inter let changed = false if (Unit.isAtomic(unit) && Link.isLoci(loci)) { for (const b of loci.links) { - const unitIdx = Unit.findUnitById(b.aUnit.id, group.units) - if (unitIdx !== -1) { + const unitIdx = group.unitIndexMap.get(b.aUnit.id) + if (unitIdx !== undefined) { const idx = unit.links.getDirectedEdgeIndex(b.aIndex, b.bIndex) if (idx !== -1) { if (apply(Interval.ofSingleton(idx))) changed = true diff --git a/src/mol-geo/representation/structure/visual/util/element.ts b/src/mol-geo/representation/structure/visual/util/element.ts index 704b0632e25ede6b55cd1354539597b937cd5cfe..0de1861eefddaeac2d28b8d6e8f20790f4eca963 100644 --- a/src/mol-geo/representation/structure/visual/util/element.ts +++ b/src/mol-geo/representation/structure/visual/util/element.ts @@ -57,8 +57,8 @@ export function markElement(loci: Loci, group: Unit.SymmetryGroup, apply: (inter let changed = false if (StructureElement.isLoci(loci)) { for (const e of loci.elements) { - const unitIdx = Unit.findUnitById(e.unit.id, group.units) - if (unitIdx !== -1) { + const unitIdx = group.unitIndexMap.get(e.unit.id) + if (unitIdx !== undefined) { if (Interval.is(e.indices)) { const start = unitIdx * elementCount + Interval.start(e.indices); const end = unitIdx * elementCount + Interval.end(e.indices); diff --git a/src/mol-geo/representation/structure/visual/util/polymer.ts b/src/mol-geo/representation/structure/visual/util/polymer.ts index 22972c0bbc454cd188d365921c5203a0b0c62337..c8a66c6a42613d6925a71a40cc0e296f852f859b 100644 --- a/src/mol-geo/representation/structure/visual/util/polymer.ts +++ b/src/mol-geo/representation/structure/visual/util/polymer.ts @@ -32,6 +32,8 @@ export function getGapRanges(unit: Unit): SortedRanges<ElementIndex> { } } +// polymer element + export function getPolymerElementCount(unit: Unit) { let count = 0 const { elements } = unit @@ -108,6 +110,8 @@ export namespace PolymerLocationIterator { } } +// polymer gap + export function getPolymerGapCount(unit: Unit) { let count = 0 const { elements } = unit diff --git a/src/mol-model/structure/structure/structure.ts b/src/mol-model/structure/structure/structure.ts index f14a7eec3522fdf24749d89ffa449a9a884b6f6b..dcdfaba17fd5422b31985f78f69385209f91fb2c 100644 --- a/src/mol-model/structure/structure/structure.ts +++ b/src/mol-model/structure/structure/structure.ts @@ -25,7 +25,9 @@ import { Vec3 } from 'mol-math/linear-algebra'; import { idFactory } from 'mol-util/id-factory'; class Structure { + /** Maps unit.id to unit */ readonly unitMap: IntMap<Unit>; + /** Array of all units in the structure, sorted by unit.id */ readonly units: ReadonlyArray<Unit>; private _props: { @@ -67,6 +69,7 @@ class Structure { return hash; } + /** Returns a new element location iterator */ elementLocations(): Iterator<StructureElement> { return new Structure.ElementLocationIterator(this); } diff --git a/src/mol-model/structure/structure/symmetry.ts b/src/mol-model/structure/structure/symmetry.ts index e3e9c4b6b4b3a8fa45a5a8dc8aef1f7ded41598b..1b35f8341f75d86dccf08e88b08cc8a475e3506f 100644 --- a/src/mol-model/structure/structure/symmetry.ts +++ b/src/mol-model/structure/structure/symmetry.ts @@ -1,7 +1,8 @@ /** - * Copyright (c) 2017 mol* contributors, licensed under MIT, See LICENSE file for more info. + * Copyright (c) 2017-2018 mol* contributors, licensed under MIT, See LICENSE file for more info. * * @author David Sehnal <david.sehnal@gmail.com> + * @author Alexander Rose <alexander.rose@weirdbyte.de> */ import Structure from './structure' @@ -10,7 +11,7 @@ import { ModelSymmetry } from '../model' import { Task, RuntimeContext } from 'mol-task'; import { SortedArray } from 'mol-data/int'; import Unit from './unit'; -import { EquivalenceClasses, hash2 } from 'mol-data/util'; +import { EquivalenceClasses } from 'mol-data/util'; import { Vec3 } from 'mol-math/linear-algebra'; import { SymmetryOperator, Spacegroup, SpacegroupCell } from 'mol-math/geometry'; @@ -58,16 +59,12 @@ namespace StructureSymmetry { return Task.create('Build NCS', ctx => _buildNCS(ctx, structure)); } - function hashUnit(u: Unit) { - return hash2(u.invariantId, SortedArray.hashCode(u.elements)); - } - export function areUnitsEquivalent(a: Unit, b: Unit) { return a.invariantId === b.invariantId && a.model.id === b.model.id && SortedArray.areEqual(a.elements, b.elements); } export function UnitEquivalenceBuilder() { - return EquivalenceClasses<number, Unit>(hashUnit, areUnitsEquivalent); + return EquivalenceClasses<number, Unit>(Unit.hashUnit, areUnitsEquivalent); } export function computeTransformGroups(s: Structure): ReadonlyArray<Unit.SymmetryGroup> { @@ -76,12 +73,7 @@ namespace StructureSymmetry { const ret: Unit.SymmetryGroup[] = []; for (const eqUnits of groups.groups) { - const first = s.unitMap.get(eqUnits[0]); - ret.push({ - elements: first.elements, - units: eqUnits.map(id => s.unitMap.get(id)), - hashCode: hashUnit(first) - }); + ret.push(Unit.SymmetryGroup(eqUnits.map(id => s.unitMap.get(id)))) } return ret; diff --git a/src/mol-model/structure/structure/unit.ts b/src/mol-model/structure/structure/unit.ts index 5cb3aeae4f8157afa51b5804caad28b311f3ec4a..c7014ae582fd6cc11ebddfc028bd50f974f51c0b 100644 --- a/src/mol-model/structure/structure/unit.ts +++ b/src/mol-model/structure/structure/unit.ts @@ -2,6 +2,7 @@ * Copyright (c) 2017-2018 mol* contributors, licensed under MIT, See LICENSE file for more info. * * @author David Sehnal <david.sehnal@gmail.com> + * @author Alexander Rose <alexander.rose@weirdbyte.de> */ import { SymmetryOperator } from 'mol-math/geometry/symmetry-operator' @@ -13,6 +14,8 @@ import { ValueRef } from 'mol-util'; import { UnitRings } from './unit/rings'; import StructureElement from './element' import { ChainIndex, ResidueIndex } from '../model/indexing'; +import { IntMap, SortedArray } from 'mol-data/int'; +import { hash2 } from 'mol-data/util'; // A building block of a structure that corresponds to an atomic or a coarse grained representation // 'conveniently grouped together'. @@ -36,21 +39,44 @@ namespace Unit { /** A group of units that differ only by symmetry operators. */ export type SymmetryGroup = { - readonly elements: StructureElement.Set, + readonly elements: StructureElement.Set readonly units: ReadonlyArray<Unit> + /** Maps unit.id to index of unit in units array */ + readonly unitIndexMap: IntMap<number> readonly hashCode: number } + function getUnitIndexMap(units: Unit[]) { + const unitIndexMap = IntMap.Mutable<number>(); + for (let i = 0, _i = units.length; i < _i; i++) { + unitIndexMap.set(units[i].id, i); + } + return unitIndexMap + } + + export function SymmetryGroup(units: Unit[]) { + const props: { + unitIndexMap?: IntMap<number> + } = {} + + return { + elements: units[0].elements, + units, + get unitIndexMap () { + if (props.unitIndexMap) return props.unitIndexMap + props.unitIndexMap = getUnitIndexMap(units) + return props.unitIndexMap + }, + hashCode: hashUnit(units[0]) + } + } + export function conformationId (unit: Unit) { return Unit.isAtomic(unit) ? unit.model.atomicConformation.id : unit.model.coarseConformation.id } - /** Find index of unit with given id, returns -1 if not found */ - export function findUnitById(id: number, units: ReadonlyArray<Unit>) { - for (let i = 0, il = units.length; i < il; ++i) { - if (units[i].id === id) return i - } - return -1 + export function hashUnit(u: Unit) { + return hash2(u.invariantId, SortedArray.hashCode(u.elements)); } export interface Base {