diff --git a/src/mol-math/geometry/symmetry-operator.ts b/src/mol-math/geometry/symmetry-operator.ts index fe6cbc7aa04ca0deaa8869cb4afbe7998fc7669e..8f9cac24028275ce2a8882e3859e1bd8c8e63c87 100644 --- a/src/mol-math/geometry/symmetry-operator.ts +++ b/src/mol-math/geometry/symmetry-operator.ts @@ -18,13 +18,13 @@ interface SymmetryOperator { } namespace SymmetryOperator { - export const DefaultName = '1_555' + export const DefaultName = 'identity' export const Default: SymmetryOperator = create(DefaultName, Mat4.identity()); const RotationEpsilon = 0.0001; export function create(name: string, matrix: Mat4, hkl?: Vec3): SymmetryOperator { - const _hkl = hkl ? Vec3.copy(Vec3.zero(), hkl) : Vec3.zero(); + const _hkl = hkl ? Vec3.clone(hkl) : Vec3.zero(); if (Mat4.isIdentity(matrix)) return { name, matrix, inverse: Mat4.identity(), isIdentity: true, hkl: _hkl }; if (!Mat4.isRotationAndTranslation(matrix, RotationEpsilon)) throw new Error(`Symmetry operator (${name}) must be a composition of rotation and translation.`); return { name, matrix, inverse: Mat4.invert(Mat4.zero(), matrix), isIdentity: false, hkl: _hkl }; diff --git a/src/mol-model/structure/model/formats/mmcif.ts b/src/mol-model/structure/model/formats/mmcif.ts index 6f135c7209df51cbb0721bc969a8510205f0711e..33c5897d3926237165403caff080e613b97daff5 100644 --- a/src/mol-model/structure/model/formats/mmcif.ts +++ b/src/mol-model/structure/model/formats/mmcif.ts @@ -144,6 +144,7 @@ function createModel(format: mmCIF_Format, bounds: Interval, previous?: Model): return { id: UUID.create(), + label: format.data.entry.id.value(0), sourceData: format, modelNum: format.data.atom_site.pdbx_PDB_model_num.value(Interval.start(bounds)), entities, diff --git a/src/mol-model/structure/model/model.ts b/src/mol-model/structure/model/model.ts index 1053bde91c2382c05f3a64445ae12facec884b62..214dc8d8687ce1b59cfd871513163622b2162420 100644 --- a/src/mol-model/structure/model/model.ts +++ b/src/mol-model/structure/model/model.ts @@ -23,6 +23,7 @@ import from_mmCIF from './formats/mmcif' */ interface Model extends Readonly<{ id: UUID, + label: string, modelNum: number, diff --git a/src/mol-model/structure/structure/structure.ts b/src/mol-model/structure/structure/structure.ts index bbc7b301d63319d52e34c354e27ef0d816fb44bd..88abc99496ed3bc540ea936dbc6c3764e49d2447 100644 --- a/src/mol-model/structure/structure/structure.ts +++ b/src/mol-model/structure/structure/structure.ts @@ -92,7 +92,8 @@ namespace Structure { for (let c = 0; c < chains.count; c++) { const elements = SortedArray.ofBounds(chains.segments[c], chains.segments[c + 1]); - builder.addUnit(Unit.Kind.Atomic, model, SymmetryOperator.Default, elements); + const label = SymmetryOperator.Default.name + builder.addUnit(label, Unit.Kind.Atomic, model, SymmetryOperator.Default, elements); } const cs = model.coarseHierarchy; @@ -112,15 +113,16 @@ namespace Structure { const { chainSegments } = elements; for (let cI = 0; cI < chainSegments.count; cI++) { const elements = SortedArray.ofBounds(chainSegments.segments[cI], chainSegments.segments[cI + 1]); - builder.addUnit(kind, model, SymmetryOperator.Default, elements); + const label = SymmetryOperator.Default.name + builder.addUnit(label, kind, model, SymmetryOperator.Default, elements); } } export class StructureBuilder { private units: Unit[] = []; - addUnit(kind: Unit.Kind, model: Model, operator: SymmetryOperator, elements: SortedArray): Unit { - const unit = Unit.create(this.units.length, kind, model, operator, elements); + addUnit(label: string, kind: Unit.Kind, model: Model, operator: SymmetryOperator, elements: SortedArray): Unit { + const unit = Unit.create(this.units.length, label, kind, model, operator, elements); this.units.push(unit); return unit; } diff --git a/src/mol-model/structure/structure/unit.ts b/src/mol-model/structure/structure/unit.ts index 5c34fd555248e6b3c2cf752446930b7d47116f6e..8c6e715eacfbca24beadfa8bab3d6fa7e35e7c62 100644 --- a/src/mol-model/structure/structure/unit.ts +++ b/src/mol-model/structure/structure/unit.ts @@ -25,11 +25,11 @@ namespace Unit { export function isSpheres(u: Unit): u is Spheres { return u.kind === Kind.Spheres; } export function isGaussians(u: Unit): u is Gaussians { return u.kind === Kind.Gaussians; } - export function create(id: number, kind: Kind, model: Model, operator: SymmetryOperator, elements: SortedArray): Unit { + export function create(id: number, label: string, kind: Kind, model: Model, operator: SymmetryOperator, elements: SortedArray): Unit { switch (kind) { - case Kind.Atomic: return new Atomic(id, unitIdFactory(), model, elements, SymmetryOperator.createMapping(operator, model.atomicConformation), AtomicProperties()); - case Kind.Spheres: return createCoarse(id, unitIdFactory(), model, Kind.Spheres, elements, SymmetryOperator.createMapping(operator, model.coarseConformation.spheres)); - case Kind.Gaussians: return createCoarse(id, unitIdFactory(), model, Kind.Gaussians, elements, SymmetryOperator.createMapping(operator, model.coarseConformation.gaussians)); + case Kind.Atomic: return new Atomic(id, unitIdFactory(), label, model, elements, SymmetryOperator.createMapping(operator, model.atomicConformation), AtomicProperties()); + case Kind.Spheres: return createCoarse(id, unitIdFactory(), label, model, Kind.Spheres, elements, SymmetryOperator.createMapping(operator, model.coarseConformation.spheres)); + case Kind.Gaussians: return createCoarse(id, unitIdFactory(), label, model, Kind.Gaussians, elements, SymmetryOperator.createMapping(operator, model.coarseConformation.gaussians)); } } @@ -40,6 +40,7 @@ namespace Unit { readonly id: number, // invariant ID stays the same even if the Operator/conformation changes. readonly invariantId: number, + readonly label: string, readonly elements: SortedArray, readonly model: Model, readonly conformation: SymmetryOperator.ArrayMapping, @@ -64,6 +65,7 @@ namespace Unit { readonly id: number; readonly invariantId: number; + readonly label: string; readonly elements: SortedArray; readonly model: Model; readonly conformation: SymmetryOperator.ArrayMapping; @@ -76,12 +78,13 @@ namespace Unit { getChild(elements: SortedArray): Unit { if (elements.length === this.elements.length) return this; - return new Atomic(this.id, this.invariantId, this.model, elements, this.conformation, AtomicProperties()); + return new Atomic(this.id, this.invariantId, this.label, this.model, elements, this.conformation, AtomicProperties()); } applyOperator(id: number, operator: SymmetryOperator, dontCompose = false): Unit { const op = dontCompose ? operator : SymmetryOperator.compose(this.conformation.operator, operator); - return new Atomic(id, this.invariantId, this.model, this.elements, SymmetryOperator.createMapping(op, this.model.atomicConformation), this.props); + const label = operator.name + return new Atomic(id, this.invariantId, label, this.model, this.elements, SymmetryOperator.createMapping(op, this.model.atomicConformation), this.props); } get lookup3d() { @@ -97,9 +100,10 @@ namespace Unit { return this.props.bonds.ref; } - constructor(id: number, invariantId: number, model: Model, elements: SortedArray, conformation: SymmetryOperator.ArrayMapping, props: AtomicProperties) { + constructor(id: number, invariantId: number, label: string, model: Model, elements: SortedArray, conformation: SymmetryOperator.ArrayMapping, props: AtomicProperties) { this.id = id; this.invariantId = invariantId; + this.label = label; this.model = model; this.elements = elements; this.conformation = conformation; @@ -124,6 +128,7 @@ namespace Unit { readonly id: number; readonly invariantId: number; + readonly label: string; readonly elements: SortedArray; readonly model: Model; readonly conformation: SymmetryOperator.ArrayMapping; @@ -133,12 +138,13 @@ namespace Unit { getChild(elements: SortedArray): Unit { if (elements.length === this.elements.length) return this as any as Unit /** lets call this an ugly temporary hack */; - return createCoarse(this.id, this.invariantId, this.model, this.kind, elements, this.conformation); + return createCoarse(this.id, this.invariantId, this.label, this.model, this.kind, elements, this.conformation); } applyOperator(id: number, operator: SymmetryOperator, dontCompose = false): Unit { const op = dontCompose ? operator : SymmetryOperator.compose(this.conformation.operator, operator); - const ret = createCoarse(id, this.invariantId, this.model, this.kind, this.elements, SymmetryOperator.createMapping(op, this.getCoarseElements())); + const label = operator.name + const ret = createCoarse(id, this.invariantId, label, this.model, this.kind, this.elements, SymmetryOperator.createMapping(op, this.getCoarseElements())); (ret as Coarse<K, C>)._lookup3d = this._lookup3d; return ret; } @@ -156,10 +162,11 @@ namespace Unit { return this.kind === Kind.Spheres ? this.model.coarseConformation.spheres : this.model.coarseConformation.gaussians; } - constructor(id: number, invariantId: number, model: Model, kind: K, elements: SortedArray, conformation: SymmetryOperator.ArrayMapping) { + constructor(id: number, invariantId: number, label: string, model: Model, kind: K, elements: SortedArray, conformation: SymmetryOperator.ArrayMapping) { this.kind = kind; this.id = id; this.invariantId = invariantId; + this.label = label; this.model = model; this.elements = elements; this.conformation = conformation; @@ -168,8 +175,8 @@ namespace Unit { } } - function createCoarse<K extends Kind.Gaussians | Kind.Spheres>(id: number, invariantId: number, model: Model, kind: K, elements: SortedArray, conformation: SymmetryOperator.ArrayMapping): Unit { - return new Coarse(id, invariantId, model, kind, elements, conformation) as any as Unit /** lets call this an ugly temporary hack */; + function createCoarse<K extends Kind.Gaussians | Kind.Spheres>(id: number, invariantId: number, label: string, model: Model, kind: K, elements: SortedArray, conformation: SymmetryOperator.ArrayMapping): Unit { + return new Coarse(id, invariantId, label, model, kind, elements, conformation) as any as Unit /** lets call this an ugly temporary hack */; } export class Spheres extends Coarse<Kind.Spheres, CoarseSphereConformation> { }