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 1237923f8ff594a22a1b66ef17dfd7fabaae3e4e..4ab1548d5fdda9a642b40eefc8d23c49e9d2693d 100644 --- a/src/mol-geo/representation/structure/visual/polymer-backbone-cylinder.ts +++ b/src/mol-geo/representation/structure/visual/polymer-backbone-cylinder.ts @@ -7,7 +7,7 @@ import { ValueCell } from 'mol-util/value-cell' import { createMeshRenderObject, MeshRenderObject } from 'mol-gl/render-object' -import { Unit, Element, StructureProperties } from 'mol-model/structure'; +import { Unit } from 'mol-model/structure'; import { DefaultStructureProps, UnitsVisual } from '../index'; import { RuntimeContext } from 'mol-task' import { createTransforms, createColors } from './util/common'; @@ -16,101 +16,36 @@ import { MeshValues } from 'mol-gl/renderable'; import { getMeshData } from '../../../util/mesh-data'; import { Mesh } from '../../../shape/mesh'; import { PickingId } from '../../../util/picking'; -import { Segmentation } from 'mol-data/int'; import { createMarkers, MarkerAction } from '../../../util/marker-data'; -import { Loci, EmptyLoci } from 'mol-model/loci'; +import { Loci } from 'mol-model/loci'; import { SizeTheme } from '../../../theme'; import { createMeshValues, updateMeshValues, updateRenderableState, createRenderableState, DefaultMeshProps } from '../../util'; import { MeshBuilder } from '../../../shape/mesh-builder'; -import { Vec3 } from 'mol-math/linear-algebra'; -import { getPolymerElementCount } from './util/polymer'; -import { MoleculeType } from 'mol-model/structure/model/types'; +import { getPolymerElementCount, PolymerBackboneIterator } from './util/polymer'; +import { getElementLoci, markElement } from './util/element'; async function createPolymerBackboneCylinderMesh(ctx: RuntimeContext, unit: Unit, mesh?: Mesh) { const polymerElementCount = getPolymerElementCount(unit) + console.log('polymerElementCount backbone', polymerElementCount) if (!polymerElementCount) return Mesh.createEmpty(mesh) // TODO better vertex count estimates const builder = MeshBuilder.create(polymerElementCount * 30, polymerElementCount * 30 / 2, mesh) - const chemCompMap = unit.model.properties.chemicalComponentMap - const { elements } = unit - const curV = Vec3.zero() - const prevV = Vec3.zero() - const pos = unit.conformation.invariantPosition - const l = Element.Location(unit) - - if (Unit.isAtomic(unit)) { - const { polymerSegments, residueSegments } = unit.model.atomicHierarchy - const polymerIt = Segmentation.transientSegments(polymerSegments, elements); - const residuesIt = Segmentation.transientSegments(residueSegments, elements); - - let i = 0 - let first = true - - while (polymerIt.hasNext) { - const polymerSegment = polymerIt.move(); - residuesIt.setSegment(polymerSegment); - first = true - while (residuesIt.hasNext) { - const residueSegment = residuesIt.move(); - l.element = elements[residueSegment.start]; - - const compId = StructureProperties.residue.label_comp_id(l) - const cc = chemCompMap.get(compId) - const moleculeType = cc ? cc.moleculeType : MoleculeType.unknown - let traceName = '' - if (moleculeType === MoleculeType.protein) { - traceName = 'CA' - } else if (moleculeType === MoleculeType.DNA || moleculeType === MoleculeType.RNA) { - traceName = 'P' - } - - for (let j = residueSegment.start, _j = residueSegment.end; j < _j; j++) { - l.element = elements[j]; - if (StructureProperties.atom.label_atom_id(l) === traceName) break - } - pos(l.element, curV) - - if (!first) { - builder.setId(residueSegment.start) - builder.addCylinder(prevV, curV, 1, { radiusTop: 0.2, radiusBottom: 0.2 }) - } else { - first = false - } - - Vec3.copy(prevV, curV) - - if (i % 10000 === 0 && ctx.shouldUpdate) { - await ctx.update({ message: 'Backbone mesh', current: i, max: polymerElementCount }); - } - ++i - } - } - } else if (Unit.isSpheres(unit)) { - let prevSeqIdEnd = -1 - for (let i = 0, il = elements.length; i < il; ++i) { - l.element = elements[i] - if (StructureProperties.entity.type(l) !== 'polymer') continue; - - pos(elements[i], curV) - const seqIdBegin = StructureProperties.coarse.seq_id_begin(l) - const seqIdEnd = StructureProperties.coarse.seq_id_end(l) - - pos(elements[i], curV) - - if (seqIdBegin - 1 === prevSeqIdEnd) { - builder.setId(i) - builder.addCylinder(prevV, curV, 1, { radiusTop: 0.2, radiusBottom: 0.2 }) - } - - Vec3.copy(prevV, curV) - prevSeqIdEnd = seqIdEnd - - if (i % 10000 === 0 && ctx.shouldUpdate) { - await ctx.update({ message: 'Backbone mesh', current: i, max: polymerElementCount }); - } + let i = 0 + const polymerTraceIt = PolymerBackboneIterator(unit) + while (polymerTraceIt.hasNext) { + const { indexA, indexB, posA, posB } = polymerTraceIt.move() + builder.setId(indexA) + // TODO size theme + builder.addCylinder(posA, posB, 0.5, { radiusTop: 0.2, radiusBottom: 0.2 }) + builder.setId(indexB) + builder.addCylinder(posB, posA, 0.5, { radiusTop: 0.2, radiusBottom: 0.2 }) + + if (i % 10000 === 0 && ctx.shouldUpdate) { + await ctx.update({ message: 'Backbone mesh', current: i, max: polymerElementCount }); } + ++i } return builder.getMesh() @@ -145,14 +80,10 @@ export function PolymerBackboneVisual(): UnitsVisual<PolymerBackboneProps> { mesh = unitKinds.includes(unit.kind) ? await createPolymerBackboneCylinderMesh(ctx, unit, mesh) : Mesh.createEmpty(mesh) + console.log(mesh) - if (ctx.shouldUpdate) await ctx.update('Computing trace transforms'); const transforms = createTransforms(group) - - if (ctx.shouldUpdate) await ctx.update('Computing trace colors'); const color = createColors(group, elementCount, colorTheme) - - if (ctx.shouldUpdate) await ctx.update('Computing trace marks'); const marker = createMarkers(instanceCount * elementCount) const counts = { drawCount: mesh.triangleCount * 3, elementCount, instanceCount } @@ -164,6 +95,7 @@ export function PolymerBackboneVisual(): UnitsVisual<PolymerBackboneProps> { aTransform: transforms, elements: mesh.indexBuffer, ...createMeshValues(currentProps, counts), + aColor: ValueCell.create(new Float32Array(mesh.vertexCount * 3)) } const state = createRenderableState(currentProps) @@ -200,11 +132,10 @@ export function PolymerBackboneVisual(): UnitsVisual<PolymerBackboneProps> { return true }, getLoci(pickingId: PickingId) { - // TODO - return EmptyLoci + return getElementLoci(renderObject.id, currentGroup, pickingId) }, mark(loci: Loci, action: MarkerAction) { - // TODO + markElement(renderObject.values.tMarker, currentGroup, loci, action) }, destroy() { // TODO 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 c5fa69d17e8b9c52f4416e2e8762d4dac700b755..75cccb7ab0beb27269f970193c61f32af954975a 100644 --- a/src/mol-geo/representation/structure/visual/polymer-trace-mesh.ts +++ b/src/mol-geo/representation/structure/visual/polymer-trace-mesh.ts @@ -7,7 +7,7 @@ import { ValueCell } from 'mol-util/value-cell' import { createMeshRenderObject, MeshRenderObject } from 'mol-gl/render-object' -import { Unit, Element, StructureProperties } from 'mol-model/structure'; +import { Unit, Element } from 'mol-model/structure'; import { DefaultStructureProps, UnitsVisual } from '../index'; import { RuntimeContext } from 'mol-task' import { createTransforms, createColors } from './util/common'; @@ -17,14 +17,13 @@ import { MeshValues } from 'mol-gl/renderable'; import { getMeshData } from '../../../util/mesh-data'; import { Mesh } from '../../../shape/mesh'; import { PickingId } from '../../../util/picking'; -import { OrderedSet, Segmentation } from 'mol-data/int'; +import { OrderedSet } from 'mol-data/int'; import { createMarkers, MarkerAction } from '../../../util/marker-data'; import { Loci, EmptyLoci } from 'mol-model/loci'; import { SizeTheme } from '../../../theme'; import { createMeshValues, updateMeshValues, updateRenderableState, createRenderableState, DefaultMeshProps } from '../../util'; import { MeshBuilder } from '../../../shape/mesh-builder'; -import { Vec3 } from 'mol-math/linear-algebra'; -import { getPolymerElementCount } from './util/polymer'; +import { getPolymerElementCount, PolymerBackboneIterator } from './util/polymer'; async function createPolymerTraceMesh(ctx: RuntimeContext, unit: Unit, mesh?: Mesh) { const polymerElementCount = getPolymerElementCount(unit) @@ -34,77 +33,20 @@ async function createPolymerTraceMesh(ctx: RuntimeContext, unit: Unit, mesh?: Me // TODO better vertex count estimates const builder = MeshBuilder.create(polymerElementCount * 30, polymerElementCount * 30 / 2, mesh) - const { elements } = unit - const curV = Vec3.zero() - const prevV = Vec3.zero() - const pos = unit.conformation.invariantPosition - const l = Element.Location(unit) - - if (Unit.isAtomic(unit)) { - const { chainSegments, residueSegments } = unit.model.atomicHierarchy - const chainsIt = Segmentation.transientSegments(chainSegments, elements); - const residuesIt = Segmentation.transientSegments(residueSegments, elements); - - let i = 0 - let prevSeqId = -1 - - while (chainsIt.hasNext) { - const chainSegment = chainsIt.move(); - residuesIt.setSegment(chainSegment); - while (residuesIt.hasNext) { - const residueSegment = residuesIt.move(); - l.element = elements[residueSegment.start]; - if (StructureProperties.entity.type(l) !== 'polymer') continue; - - const seqId = StructureProperties.residue.label_seq_id(l) - - // for (let j = residueSegment.start, _j = residueSegment.end; j < _j; j++) { - // l.element = elements[j]; - // } - // TODO get proper trace element - pos(l.element, curV) - - if (seqId - 1 === prevSeqId) { - // TODO draw trace - builder.setId(residueSegment.start) - builder.addCylinder(prevV, curV, 1, { radiusTop: 0.2, radiusBottom: 0.2 }) - } - - Vec3.copy(prevV, curV) - prevSeqId = seqId - - if (i % 10000 === 0 && ctx.shouldUpdate) { - await ctx.update({ message: 'Cartoon mesh', current: i, max: polymerElementCount }); - } - ++i - } - } - } else if (Unit.isSpheres(unit)) { - let prevSeqIdEnd = -1 - for (let i = 0, il = elements.length; i < il; ++i) { - l.element = elements[i] - if (StructureProperties.entity.type(l) !== 'polymer') continue; - // console.log(elementLabel(l), StructureProperties.entity.type(l)) - - pos(elements[i], curV) - const seqIdBegin = StructureProperties.coarse.seq_id_begin(l) - const seqIdEnd = StructureProperties.coarse.seq_id_end(l) - - pos(elements[i], curV) - - if (seqIdBegin - 1 === prevSeqIdEnd) { - // TODO draw trace - builder.setId(i) - builder.addCylinder(prevV, curV, 1, { radiusTop: 0.2, radiusBottom: 0.2 }) - } - - Vec3.copy(prevV, curV) - prevSeqIdEnd = seqIdEnd - - if (i % 10000 === 0 && ctx.shouldUpdate) { - await ctx.update({ message: 'Backbone mesh', current: i, max: polymerElementCount }); - } + let i = 0 + const polymerTraceIt = PolymerBackboneIterator(unit) + while (polymerTraceIt.hasNext) { + const v = polymerTraceIt.move() + builder.setId(v.indexA) + // TODO size theme + builder.addCylinder(v.posA, v.posB, 0.5, { radiusTop: 0.2, radiusBottom: 0.2 }) + builder.setId(v.indexB) + builder.addCylinder(v.posB, v.posA, 0.5, { radiusTop: 0.2, radiusBottom: 0.2 }) + + if (i % 10000 === 0 && ctx.shouldUpdate) { + await ctx.update({ message: 'Backbone mesh', current: i, max: polymerElementCount }); } + ++i } return builder.getMesh() diff --git a/src/mol-geo/representation/structure/visual/util/polymer.ts b/src/mol-geo/representation/structure/visual/util/polymer.ts index 3f8c7bf3f9ff5dfa156f9de0ff57b38bdd6bac1d..b663fc5a08ffbbeeb0e0ba988ed94b9cc7f51bb0 100644 --- a/src/mol-geo/representation/structure/visual/util/polymer.ts +++ b/src/mol-geo/representation/structure/visual/util/polymer.ts @@ -6,7 +6,11 @@ import { Unit, Element, StructureProperties } from 'mol-model/structure'; import { Segmentation } from 'mol-data/int'; -// import Iterator from 'mol-data/iterator'; +import { MoleculeType } from 'mol-model/structure/model/types'; +import Iterator from 'mol-data/iterator'; +import { SegmentIterator } from 'mol-data/int/impl/segmentation'; +import { Vec3 } from 'mol-math/linear-algebra'; +import { SymmetryOperator } from 'mol-math/geometry'; export function getPolymerElementCount(unit: Unit) { let count = 0 @@ -32,62 +36,308 @@ export function getPolymerElementCount(unit: Unit) { return count } -// interface PolymerTrace { -// center: Element -// direction: Element -// } - -// export class PolymerTraceIterator<T extends number = number> implements Iterator<PolymerTrace> { -// private segmentMin = 0; -// private segmentMax = 0; -// private setRange = Interval.Empty; -// private value: TraceSegment = { index: 0, start: 0 as T, end: 0 as T }; - -// hasNext: boolean = false; - -// move() { -// while (this.hasNext) { -// if (this.updateValue()) { -// this.value.index = this.segmentMin++; -// this.hasNext = this.segmentMax >= this.segmentMin && Interval.size(this.setRange) > 0; -// break; -// } else { -// this.updateSegmentRange(); -// } -// } -// return this.value; -// } - -// private updateValue() { -// const segmentEnd = this.segments[this.segmentMin + 1]; -// // TODO: add optimized version for interval and array? -// const setEnd = OrderedSet.findPredecessorIndexInInterval(this.set, segmentEnd, this.setRange); -// this.value.start = Interval.start(this.setRange) as T; -// this.value.end = setEnd as T; -// this.setRange = Interval.ofBounds(setEnd, Interval.end(this.setRange)); -// return setEnd > this.value.start; -// } - -// private updateSegmentRange() { -// const sMin = Interval.min(this.setRange), sMax = Interval.max(this.setRange); -// if (sMax < sMin) { -// this.hasNext = false; -// return; -// } - -// this.segmentMin = this.segmentMap[OrderedSet.getAt(this.set, sMin)]; -// this.segmentMax = this.segmentMap[OrderedSet.getAt(this.set, sMax)]; - -// this.hasNext = this.segmentMax >= this.segmentMin; -// } - -// setSegment(segment: Segs.Segment<T>) { -// this.setRange = Interval.ofBounds(segment.start, segment.end); -// this.updateSegmentRange(); -// } - -// constructor(private segments: SortedArray, private segmentMap: Int32Array, private set: OrderedSet, inputRange: Interval) { -// this.setRange = inputRange; -// this.updateSegmentRange(); -// } -// } \ No newline at end of file +function getTraceName(l: Element.Location) { + const compId = StructureProperties.residue.label_comp_id(l) + const chemCompMap = l.unit.model.properties.chemicalComponentMap + const cc = chemCompMap.get(compId) + const moleculeType = cc ? cc.moleculeType : MoleculeType.unknown + let traceName = '' + if (moleculeType === MoleculeType.protein) { + traceName = 'CA' + } else if (moleculeType === MoleculeType.DNA || moleculeType === MoleculeType.RNA) { + traceName = 'P' + } + return traceName +} + +function setTraceElement(l: Element.Location, residueSegment: Segmentation.Segment<Element>) { + const elements = l.unit.elements + l.element = elements[residueSegment.start] + const traceName = getTraceName(l) + + for (let j = residueSegment.start, _j = residueSegment.end; j < _j; j++) { + l.element = elements[j]; + if (StructureProperties.atom.label_atom_id(l) === traceName) return j + } + return residueSegment.end - 1 +} + +/** Iterates over consecutive pairs of residues/coarse elements in polymers */ +export function PolymerBackboneIterator(unit: Unit): Iterator<PolymerBackbonePair> { + switch (unit.kind) { + case Unit.Kind.Atomic: return new AtomicPolymerBackboneIterator(unit) + case Unit.Kind.Spheres: + case Unit.Kind.Gaussians: + return new CoarsePolymerBackboneIterator(unit) + } +} + +interface PolymerBackbonePair { + centerA: Element.Location + centerB: Element.Location + indexA: number + indexB: number + posA: Vec3 + posB: Vec3 +} + +function createPolymerBackbonePair (unit: Unit) { + return { + centerA: Element.Location(unit), + centerB: Element.Location(unit), + indexA: 0, + indexB: 0, + posA: Vec3.zero(), + posB: Vec3.zero() + } +} + +const enum AtomicPolymerBackboneIteratorState { nextPolymer, firstResidue, nextResidue } + +export class AtomicPolymerBackboneIterator<T extends number = number> implements Iterator<PolymerBackbonePair> { + private value: PolymerBackbonePair + + private polymerIt: SegmentIterator<Element> + private residueIt: SegmentIterator<Element> + private polymerSegment: Segmentation.Segment<Element> + private state: AtomicPolymerBackboneIteratorState = AtomicPolymerBackboneIteratorState.nextPolymer + private pos: SymmetryOperator.CoordinateMapper + + hasNext: boolean = false; + + move() { + const { residueIt, polymerIt, value, pos } = this + + if (this.state === AtomicPolymerBackboneIteratorState.nextPolymer) { + if (polymerIt.hasNext) { + this.polymerSegment = polymerIt.move(); + residueIt.setSegment(this.polymerSegment); + this.state = AtomicPolymerBackboneIteratorState.firstResidue + } + } + + if (this.state === AtomicPolymerBackboneIteratorState.firstResidue) { + const residueSegment = residueIt.move(); + if (residueIt.hasNext) { + value.indexB = setTraceElement(value.centerB, residueSegment) + pos(value.centerB.element, value.posB) + this.state = AtomicPolymerBackboneIteratorState.nextResidue + } else { + this.state = AtomicPolymerBackboneIteratorState.nextPolymer + } + + } + + if (this.state === AtomicPolymerBackboneIteratorState.nextResidue) { + const residueSegment = residueIt.move(); + value.centerA.element = value.centerB.element + value.indexA = value.indexB + Vec3.copy(value.posA, value.posB) + value.indexB = setTraceElement(value.centerB, residueSegment) + pos(value.centerB.element, value.posB) + + if (!residueIt.hasNext) { + this.state = AtomicPolymerBackboneIteratorState.nextPolymer + } + } + + this.hasNext = residueIt.hasNext || polymerIt.hasNext + + return this.value; + } + + constructor(unit: Unit.Atomic) { + const { polymerSegments, residueSegments } = unit.model.atomicHierarchy + this.polymerIt = Segmentation.transientSegments(polymerSegments, unit.elements); + this.residueIt = Segmentation.transientSegments(residueSegments, unit.elements); + this.pos = unit.conformation.invariantPosition + this.value = createPolymerBackbonePair(unit) + this.hasNext = this.residueIt.hasNext || this.polymerIt.hasNext + } +} + +const enum CoarsePolymerBackboneIteratorState { nextPolymer, firstElement, nextElement } + +export class CoarsePolymerBackboneIterator<T extends number = number> implements Iterator<PolymerBackbonePair> { + private value: PolymerBackbonePair + + private polymerIt: SegmentIterator<Element> + private polymerSegment: Segmentation.Segment<Element> + private state: CoarsePolymerBackboneIteratorState = CoarsePolymerBackboneIteratorState.nextPolymer + private pos: SymmetryOperator.CoordinateMapper + private elementIndex: number + + hasNext: boolean = false; + + move() { + const { polymerIt, value, pos } = this + + if (this.state === CoarsePolymerBackboneIteratorState.nextPolymer) { + if (polymerIt.hasNext) { + this.polymerSegment = polymerIt.move(); + this.elementIndex = this.polymerSegment.start + this.state = CoarsePolymerBackboneIteratorState.firstElement + } + } + + if (this.state === CoarsePolymerBackboneIteratorState.firstElement) { + this.elementIndex += 1 + if (this.elementIndex + 1 < this.polymerSegment.end) { + value.centerB.element = value.centerB.unit.elements[this.elementIndex] + value.indexB = this.elementIndex + pos(value.centerB.element, value.posB) + + this.state = CoarsePolymerBackboneIteratorState.nextElement + } else { + this.state = CoarsePolymerBackboneIteratorState.nextPolymer + } + + } + + if (this.state === CoarsePolymerBackboneIteratorState.nextElement) { + this.elementIndex += 1 + value.centerA.element = value.centerB.element + value.indexA = value.indexB + Vec3.copy(value.posA, value.posB) + + value.centerB.element = value.centerB.unit.elements[this.elementIndex] + value.indexB = this.elementIndex + pos(value.centerB.element, value.posB) + + if (this.elementIndex + 1 >= this.polymerSegment.end) { + this.state = CoarsePolymerBackboneIteratorState.nextPolymer + } + } + + this.hasNext = this.elementIndex + 1 < this.polymerSegment.end || polymerIt.hasNext + + return this.value; + } + + constructor(unit: Unit.Spheres | Unit.Gaussians) { + const { polymerSegments } = Unit.isSpheres(unit) + ? unit.model.coarseHierarchy.spheres + : unit.model.coarseHierarchy.gaussians + this.polymerIt = Segmentation.transientSegments(polymerSegments, unit.elements); + + this.pos = unit.conformation.invariantPosition + this.value = createPolymerBackbonePair(unit) + + this.hasNext = this.polymerIt.hasNext + } +} + + + + +/** + * Iterates over individual residues/coarse elements in polymers while providing information + * about the neighbourhood in the underlying model for drawing splines + */ +export function PolymerTraceIterator(unit: Unit): Iterator<PolymerTraceElement> { + switch (unit.kind) { + case Unit.Kind.Atomic: return new AtomicPolymerTraceIterator(unit) + case Unit.Kind.Spheres: + case Unit.Kind.Gaussians: + return new CoarsePolymerTraceIterator(unit) + } +} + +interface PolymerTraceElement { + center: Element.Location + index: number + pos: Vec3 + posPrev: Vec3 + posNext: Vec3 + posNextNext: Vec3 +} + +function createPolymerTraceElement (unit: Unit) { + return { + center: Element.Location(unit), + index: 0, + pos: Vec3.zero(), + posPrev: Vec3.zero(), + posNext: Vec3.zero(), + posNextNext: Vec3.zero() + } +} + +// const enum AtomicPolymerTraceIteratorState { nextPolymer, firstResidue, nextResidue } + +export class AtomicPolymerTraceIterator<T extends number = number> implements Iterator<PolymerTraceElement> { + private value: PolymerTraceElement + + private polymerIt: SegmentIterator<Element> + private residueIt: SegmentIterator<Element> + // private polymerSegment: Segmentation.Segment<Element> + // private state: AtomicPolymerTraceIteratorState = AtomicPolymerTraceIteratorState.nextPolymer + // private pos: SymmetryOperator.CoordinateMapper + + hasNext: boolean = false; + + move() { + // const { residueIt, polymerIt, value, pos } = this + + // if (this.state === AtomicPolymerTraceIteratorState.nextPolymer) { + // if (polymerIt.hasNext) { + // this.polymerSegment = polymerIt.move(); + // residueIt.setSegment(this.polymerSegment); + // this.state = AtomicPolymerTraceIteratorState.firstResidue + // } + // } + + // if (this.state === AtomicPolymerTraceIteratorState.firstResidue) { + // const residueSegment = residueIt.move(); + // if (residueIt.hasNext) { + // value.indexB = setTraceElement(value.centerB, residueSegment) + // pos(value.centerB.element, value.posB) + // this.state = AtomicPolymerTraceIteratorState.nextResidue + // } else { + // this.state = AtomicPolymerTraceIteratorState.nextPolymer + // } + + // } + + // if (this.state === AtomicPolymerTraceIteratorState.nextResidue) { + // const residueSegment = residueIt.move(); + // value.centerA.element = value.centerB.element + // value.indexA = value.indexB + // Vec3.copy(value.posA, value.posB) + // value.indexB = setTraceElement(value.centerB, residueSegment) + // pos(value.centerB.element, value.posB) + + // if (!residueIt.hasNext) { + // this.state = AtomicPolymerTraceIteratorState.nextPolymer + // } + // } + + // this.hasNext = residueIt.hasNext || polymerIt.hasNext + + return this.value; + } + + constructor(unit: Unit.Atomic) { + const { polymerSegments, residueSegments } = unit.model.atomicHierarchy + this.polymerIt = Segmentation.transientSegments(polymerSegments, unit.elements); + this.residueIt = Segmentation.transientSegments(residueSegments, unit.elements); + // this.pos = unit.conformation.invariantPosition + this.value = createPolymerTraceElement(unit) + this.hasNext = this.residueIt.hasNext || this.polymerIt.hasNext + } +} + +export class CoarsePolymerTraceIterator<T extends number = number> implements Iterator<PolymerTraceElement> { + private value: PolymerTraceElement + + hasNext: boolean = false; + + move() { + return this.value; + } + + constructor(unit: Unit.Spheres | Unit.Gaussians) { + this.value = createPolymerTraceElement(unit) + this.hasNext = false + } +} \ No newline at end of file diff --git a/src/mol-view/stage.ts b/src/mol-view/stage.ts index 3809a7271bfb22e64a7a5ddcfdbc536f66da6b24..923423527eb39b00c3c9754983484dafb215fb1a 100644 --- a/src/mol-view/stage.ts +++ b/src/mol-view/stage.ts @@ -4,7 +4,7 @@ * @author Alexander Rose <alexander.rose@weirdbyte.de> */ -import Viewer from 'mol-view/viewer' +import Viewer from './viewer' import { StateContext } from './state/context'; import { Progress } from 'mol-task'; import { MmcifUrlToModel, ModelToStructure, StructureToSpacefill, StructureToBallAndStick, StructureToDistanceRestraint, StructureToCartoon, StructureToBackbone } from './state/transform'; @@ -15,6 +15,7 @@ import { BallAndStickProps } from 'mol-geo/representation/structure/ball-and-sti import { CartoonProps } from 'mol-geo/representation/structure/cartoon'; import { DistanceRestraintProps } from 'mol-geo/representation/structure/distance-restraint'; import { BackboneProps } from 'mol-geo/representation/structure/backbone'; +import { Queries as Q, StructureProperties as SP, Query, Selection } from 'mol-model/structure'; const spacefillProps: SpacefillProps = { doubleSided: true, @@ -26,7 +27,8 @@ const spacefillProps: SpacefillProps = { const ballAndStickProps: BallAndStickProps = { doubleSided: true, colorTheme: { name: 'chain-id' }, - sizeTheme: { name: 'uniform', value: 0.25 }, + sizeTheme: { name: 'uniform', value: 0.05 }, + linkRadius: 0.05, quality: 'auto', useFog: false } @@ -68,16 +70,20 @@ export class Stage { // this.loadPdbid('1jj2') // this.loadPdbid('4umt') // ligand has bond with order 3 - // this.loadPdbid('1crn') // small + this.loadPdbid('1crn') // small // this.loadPdbid('1rb8') // virus // this.loadPdbid('1blu') // metal coordination // this.loadPdbid('3pqr') // inter unit bonds // this.loadPdbid('4v5a') // ribosome // this.loadPdbid('3j3q') // ... - this.loadPdbid('3sn6') // ... + // this.loadPdbid('3sn6') // discontinuous chains // this.loadMmcifUrl(`../../examples/1cbs_full.bcif`) // this.loadMmcifUrl(`../../../test/pdb-dev/PDBDEV_00000001.cif`) + // this.loadMmcifUrl(`../../../test/pdb-dev/PDBDEV_00000002.cif`) + // this.loadMmcifUrl(`../../../test/pdb-dev/PDBDEV_00000003.cif`) + // this.loadMmcifUrl(`../../../test/pdb-dev/PDBDEV_00000004.cif`) + // this.loadMmcifUrl(`../../../test/pdb-dev/PDBDEV_00000005.cif`) } async loadMmcifUrl (url: string) { @@ -85,13 +91,21 @@ export class Stage { const modelEntity = await MmcifUrlToModel.apply(this.ctx, urlEntity) const structureEntity = await ModelToStructure.apply(this.ctx, modelEntity) + StructureToBallAndStick.apply(this.ctx, structureEntity, { ...ballAndStickProps, visible: true }) StructureToSpacefill.apply(this.ctx, structureEntity, { ...spacefillProps, visible: false }) - StructureToBallAndStick.apply(this.ctx, structureEntity, { ...ballAndStickProps, visible: false }) StructureToDistanceRestraint.apply(this.ctx, structureEntity, { ...distanceRestraintProps, visible: false }) - StructureToBackbone.apply(this.ctx, structureEntity, { ...backboneProps, visible: true }) + // StructureToBackbone.apply(this.ctx, structureEntity, { ...backboneProps, visible: true }) StructureToCartoon.apply(this.ctx, structureEntity, { ...cartoonProps, visible: false }) this.globalContext.components.sequenceView.setState({ structure: structureEntity.value }); + + const structureEntity2 = await ModelToStructure.apply(this.ctx, modelEntity) + const q1 = Q.generators.atoms({ + residueTest: l => SP.residue.label_seq_id(l) > 30 + }); + structureEntity2.value = Selection.unionStructure(await Query(q1)(structureEntity2.value).run()); + StructureToBackbone.apply(this.ctx, structureEntity2, { ...backboneProps, visible: true }) + StructureToCartoon.apply(this.ctx, structureEntity2, { ...cartoonProps, visible: true }) } loadPdbid (pdbid: string) {