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 03a2eeb9443c3582cf42ae8a653ed7c7bbfe89fb..8591ca379aca4372f51ec30ea854281c09c2a039 100644 --- a/src/mol-geo/representation/structure/visual/nucleotide-block-mesh.ts +++ b/src/mol-geo/representation/structure/visual/nucleotide-block-mesh.ts @@ -9,14 +9,15 @@ import { UnitsVisual } from '..'; import { RuntimeContext } from 'mol-task' import { Mesh } from '../../../mesh/mesh'; import { MeshBuilder } from '../../../mesh/mesh-builder'; -import { getElementLoci, markElement, StructureElementIterator } from './util/element'; +import { getElementLoci, markElement } from './util/element'; import { Vec3, Mat4 } from 'mol-math/linear-algebra'; -import { Segmentation, SortedArray } from 'mol-data/int'; +import { Segmentation } from 'mol-data/int'; import { MoleculeType, isNucleic, isPurinBase, isPyrimidineBase } from 'mol-model/structure/model/types'; import { getElementIndexForAtomId, getElementIndexForAtomRole } from 'mol-model/structure/util'; import { DefaultUnitsMeshProps, UnitsMeshVisual } from '../units-visual'; import { addCylinder } from '../../../mesh/builder/cylinder'; import { Box } from '../../../primitive/box'; +import { NucleotideLocationIterator } from './util/nucleotide'; const p1 = Vec3.zero() const p2 = Vec3.zero() @@ -84,7 +85,7 @@ async function createNucleotideBlockMesh(ctx: RuntimeContext, unit: Unit, props: if (idx5 !== -1 && idx6 !== -1) { pos(idx5, p5); pos(idx6, p6) - builder.setGroup(SortedArray.findPredecessorIndex(elements, idx6)) + builder.setGroup(i) addCylinder(builder, p5, p6, 1, { radiusTop: 0.2, radiusBottom: 0.2 }) if (idx1 !== -1 && idx2 !== -1 && idx3 !== -1 && idx4 !== -1) { pos(idx1, p1); pos(idx2, p2); pos(idx3, p3); pos(idx4, p4); @@ -98,12 +99,12 @@ async function createNucleotideBlockMesh(ctx: RuntimeContext, unit: Unit, props: builder.add(t, box) } } - } - if (i % 10000 === 0 && ctx.shouldUpdate) { - await ctx.update({ message: 'Nucleotide block mesh', current: i }); + if (i % 10000 === 0 && ctx.shouldUpdate) { + await ctx.update({ message: 'Nucleotide block mesh', current: i }); + } + ++i } - ++i } } @@ -119,7 +120,7 @@ export function NucleotideBlockVisual(): UnitsVisual<NucleotideBlockProps> { return UnitsMeshVisual<NucleotideBlockProps>({ defaultProps: DefaultNucleotideBlockProps, createMesh: createNucleotideBlockMesh, - createLocationIterator: StructureElementIterator.fromGroup, + createLocationIterator: NucleotideLocationIterator.fromGroup, getLoci: getElementLoci, mark: markElement, setUpdateState: () => {} 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 6ad043eba547f99896cfbc6e620c709b76dfcc7d..da3d7513ccee7ab5ec10f911074b15c10e76e4e1 100644 --- a/src/mol-geo/representation/structure/visual/polymer-direction-wedge.ts +++ b/src/mol-geo/representation/structure/visual/polymer-direction-wedge.ts @@ -7,15 +7,14 @@ import { Unit } from 'mol-model/structure'; import { UnitsVisual } from '..'; import { RuntimeContext } from 'mol-task' -import { markElement, getElementLoci, StructureElementIterator } from './util/element'; +import { markElement, getElementLoci } from './util/element'; import { Mesh } from '../../../mesh/mesh'; import { MeshBuilder } from '../../../mesh/mesh-builder'; -import { getPolymerElementCount, PolymerTraceIterator, createCurveSegmentState, interpolateCurveSegment } from './util/polymer'; +import { getPolymerElementCount, PolymerTraceIterator, createCurveSegmentState, interpolateCurveSegment, PolymerLocationIterator } from './util/polymer'; import { Vec3, Mat4 } from 'mol-math/linear-algebra'; import { SecondaryStructureType, MoleculeType } from 'mol-model/structure/model/types'; import { DefaultUnitsMeshProps, UnitsMeshVisual } from '../units-visual'; import { SizeThemeProps, SizeTheme } from 'mol-view/theme/size'; -import { OrderedSet } from 'mol-data/int'; import { Wedge } from '../../../primitive/wedge'; const t = Mat4.identity() @@ -51,7 +50,7 @@ async function createPolymerDirectionWedgeMesh(ctx: RuntimeContext, unit: Unit, const polymerTraceIt = PolymerTraceIterator(unit) while (polymerTraceIt.hasNext) { const v = polymerTraceIt.move() - builder.setGroup(OrderedSet.findPredecessorIndex(unit.elements, v.center.element)) + builder.setGroup(i) const isNucleic = v.moleculeType === MoleculeType.DNA || v.moleculeType === MoleculeType.RNA const isSheet = SecondaryStructureType.is(v.secStrucType, SecondaryStructureType.Flag.Beta) @@ -95,7 +94,7 @@ export function PolymerDirectionVisual(): UnitsVisual<PolymerDirectionProps> { return UnitsMeshVisual<PolymerDirectionProps>({ defaultProps: DefaultPolymerDirectionProps, createMesh: createPolymerDirectionWedgeMesh, - createLocationIterator: StructureElementIterator.fromGroup, + createLocationIterator: PolymerLocationIterator.fromGroup, getLoci: getElementLoci, mark: markElement, setUpdateState: () => {} 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 047850c67aae193be0cb0035aed18925e054bfcd..883e2f9e6f84ff4f83af93dfa5ed07df2f5b48b3 100644 --- a/src/mol-geo/representation/structure/visual/polymer-gap-cylinder.ts +++ b/src/mol-geo/representation/structure/visual/polymer-gap-cylinder.ts @@ -9,8 +9,8 @@ import { UnitsVisual } from '..'; import { RuntimeContext } from 'mol-task' import { Mesh } from '../../../mesh/mesh'; import { MeshBuilder } from '../../../mesh/mesh-builder'; -import { getPolymerGapCount, PolymerGapIterator } from './util/polymer'; -import { getElementLoci, markElement, StructureElementIterator } from './util/element'; +import { getPolymerGapCount, PolymerGapIterator, PolymerGapLocationIterator } from './util/polymer'; +import { getElementLoci, markElement } from './util/element'; import { Vec3 } from 'mol-math/linear-algebra'; import { UnitsMeshVisual, DefaultUnitsMeshProps } from '../units-visual'; import { SizeThemeProps, SizeTheme } from 'mol-view/theme/size'; @@ -35,11 +35,9 @@ async function createPolymerGapCylinderMesh(ctx: RuntimeContext, unit: Unit, pro const vertexCountEstimate = segmentCount * radialSegments * 2 * polymerGapCount * 2 const builder = MeshBuilder.create(vertexCountEstimate, vertexCountEstimate / 10, mesh) - const { elements } = unit const pos = unit.conformation.invariantPosition const pA = Vec3.zero() const pB = Vec3.zero() - const l = StructureElement.create(unit) const cylinderProps: CylinderProps = { radiusTop: 1, radiusBottom: 1, topCap: true, bottomCap: true, radialSegments } @@ -49,30 +47,26 @@ async function createPolymerGapCylinderMesh(ctx: RuntimeContext, unit: Unit, pro while (polymerGapIt.hasNext) { const { centerA, centerB } = polymerGapIt.move() if (centerA.element === centerB.element) { - builder.setGroup(centerA.element) - pos(elements[centerA.element], pA) + builder.setGroup(i) + pos(centerA.element, pA) addSphere(builder, pA, 0.6, 0) } else { - const elmA = elements[centerA.element] - const elmB = elements[centerB.element] - pos(elmA, pA) - pos(elmB, pB) + pos(centerA.element, pA) + pos(centerB.element, pB) - l.element = elmA - cylinderProps.radiusTop = cylinderProps.radiusBottom = sizeTheme.size(l) - builder.setGroup(centerA.element) + cylinderProps.radiusTop = cylinderProps.radiusBottom = sizeTheme.size(centerA) + builder.setGroup(i) addFixedCountDashedCylinder(builder, pA, pB, 0.5, segmentCount, cylinderProps) - l.element = elmB - cylinderProps.radiusTop = cylinderProps.radiusBottom = sizeTheme.size(l) - builder.setGroup(centerB.element) + cylinderProps.radiusTop = cylinderProps.radiusBottom = sizeTheme.size(centerB) + builder.setGroup(i + 1) addFixedCountDashedCylinder(builder, pB, pA, 0.5, segmentCount, cylinderProps) } if (i % 10000 === 0 && ctx.shouldUpdate) { await ctx.update({ message: 'Gap mesh', current: i, max: polymerGapCount }); } - ++i + i += 2 } return builder.getMesh() @@ -88,7 +82,7 @@ export function PolymerGapVisual(): UnitsVisual<PolymerGapProps> { return UnitsMeshVisual<PolymerGapProps>({ defaultProps: DefaultPolymerGapProps, createMesh: createPolymerGapCylinderMesh, - createLocationIterator: StructureElementIterator.fromGroup, + createLocationIterator: PolymerGapLocationIterator.fromGroup, getLoci: getElementLoci, mark: markElement, setUpdateState: () => {} 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 f65c7fb9cb36488df559bbe8a412d1ee03bd81f6..f5fa0efd09789fcd4a264c561273e9e59c63ddce 100644 --- a/src/mol-geo/representation/structure/visual/polymer-trace-mesh.ts +++ b/src/mol-geo/representation/structure/visual/polymer-trace-mesh.ts @@ -7,14 +7,13 @@ import { Unit } from 'mol-model/structure'; import { UnitsVisual, MeshUpdateState } from '..'; import { RuntimeContext } from 'mol-task' -import { markElement, getElementLoci, StructureElementIterator } from './util/element'; +import { markElement, getElementLoci } from './util/element'; import { Mesh } from '../../../mesh/mesh'; import { MeshBuilder } from '../../../mesh/mesh-builder'; -import { getPolymerElementCount, PolymerTraceIterator, createCurveSegmentState, interpolateCurveSegment } from './util/polymer'; +import { getPolymerElementCount, PolymerTraceIterator, createCurveSegmentState, interpolateCurveSegment, PolymerLocationIterator } from './util/polymer'; import { SecondaryStructureType, isNucleic } from 'mol-model/structure/model/types'; import { UnitsMeshVisual, DefaultUnitsMeshProps } from '../units-visual'; import { SizeThemeProps, SizeTheme } from 'mol-view/theme/size'; -import { OrderedSet } from 'mol-data/int'; import { addSheet } from '../../../mesh/builder/sheet'; import { addTube } from '../../../mesh/builder/tube'; @@ -45,7 +44,7 @@ async function createPolymerTraceMesh(ctx: RuntimeContext, unit: Unit, props: Po const polymerTraceIt = PolymerTraceIterator(unit) while (polymerTraceIt.hasNext) { const v = polymerTraceIt.move() - builder.setGroup(OrderedSet.findPredecessorIndex(unit.elements, v.center.element)) + builder.setGroup(i) const isNucleicType = isNucleic(v.moleculeType) const isSheet = SecondaryStructureType.is(v.secStrucType, SecondaryStructureType.Flag.Beta) @@ -95,7 +94,7 @@ export function PolymerTraceVisual(): UnitsVisual<PolymerTraceProps> { return UnitsMeshVisual<PolymerTraceProps>({ defaultProps: DefaultPolymerTraceProps, createMesh: createPolymerTraceMesh, - createLocationIterator: StructureElementIterator.fromGroup, + createLocationIterator: PolymerLocationIterator.fromGroup, getLoci: getElementLoci, mark: markElement, setUpdateState: (state: MeshUpdateState, newProps: PolymerTraceProps, currentProps: PolymerTraceProps) => { diff --git a/src/mol-geo/representation/structure/visual/util/nucleotide.ts b/src/mol-geo/representation/structure/visual/util/nucleotide.ts new file mode 100644 index 0000000000000000000000000000000000000000..2243e8a6bb32f1719b5f68f16b268c18bae6d49b --- /dev/null +++ b/src/mol-geo/representation/structure/visual/util/nucleotide.ts @@ -0,0 +1,51 @@ +/** + * Copyright (c) 2018 mol* contributors, licensed under MIT, See LICENSE file for more info. + * + * @author Alexander Rose <alexander.rose@weirdbyte.de> + */ +import { Unit, ElementIndex, StructureElement } from 'mol-model/structure'; +import { LocationIterator } from '../../../../util/location-iterator'; +import { Segmentation } from 'mol-data/int'; +import { isNucleic, MoleculeType } from 'mol-model/structure/model/types'; +import { getElementIndexForAtomRole } from 'mol-model/structure/util'; + +export function getNucleotideElementIndices(unit: Unit) { + const indices: ElementIndex[] = [] + const { elements, model } = unit + const { chemicalComponentMap } = model.properties + const { chainAtomSegments, residueAtomSegments, residues } = model.atomicHierarchy + const { label_comp_id } = residues + const chainIt = Segmentation.transientSegments(chainAtomSegments, elements) + const residueIt = Segmentation.transientSegments(residueAtomSegments, elements) + while (chainIt.hasNext) { + residueIt.setSegment(chainIt.move()); + + while (residueIt.hasNext) { + const { index } = residueIt.move(); + const cc = chemicalComponentMap.get(label_comp_id.value(index)) + const moleculeType = cc ? cc.moleculeType : MoleculeType.unknown + + if (isNucleic(moleculeType)) { + const elementIndex = getElementIndexForAtomRole(model, index, 'trace') + indices.push(elementIndex === -1 ? residueAtomSegments.offsets[index] : elementIndex) + } + } + } + return indices +} + +export namespace NucleotideLocationIterator { + export function fromGroup(group: Unit.SymmetryGroup): LocationIterator { + const nucleotideElementIndices = getNucleotideElementIndices(group.units[0]) + const groupCount = nucleotideElementIndices.length + const instanceCount = group.units.length + const location = StructureElement.create() + const getLocation = (groupIndex: number, instanceIndex: number) => { + const unit = group.units[instanceIndex] + location.unit = unit + location.element = nucleotideElementIndices[groupIndex] + return location + } + return LocationIterator(groupCount, instanceCount, getLocation) + } +} \ No newline at end of file diff --git a/src/mol-geo/representation/structure/visual/util/polymer.ts b/src/mol-geo/representation/structure/visual/util/polymer.ts index 24d9b7e937e2953c1e1acb3c958a6f69de6b264c..22972c0bbc454cd188d365921c5203a0b0c62337 100644 --- a/src/mol-geo/representation/structure/visual/util/polymer.ts +++ b/src/mol-geo/representation/structure/visual/util/polymer.ts @@ -4,9 +4,12 @@ * @author Alexander Rose <alexander.rose@weirdbyte.de> */ -import { Unit, ElementIndex } from 'mol-model/structure'; +import { Unit, ElementIndex, StructureElement } from 'mol-model/structure'; import { Segmentation, OrderedSet, Interval } from 'mol-data/int'; import SortedRanges from 'mol-data/int/sorted-ranges'; +import { LocationIterator } from '../../../../util/location-iterator'; +import { getElementIndexForAtomRole } from 'mol-model/structure/util'; +import { PolymerGapIterator } from './polymer/gap-iterator'; export * from './polymer/backbone-iterator' export * from './polymer/gap-iterator' @@ -57,6 +60,54 @@ export function getPolymerElementCount(unit: Unit) { return count } +export function getPolymerElementIndices(unit: Unit) { + const indices: ElementIndex[] = [] + const { elements, model } = unit + const { residueAtomSegments } = unit.model.atomicHierarchy + const polymerIt = SortedRanges.transientSegments(getPolymerRanges(unit), elements) + switch (unit.kind) { + case Unit.Kind.Atomic: + const residueIt = Segmentation.transientSegments(residueAtomSegments, elements) + while (polymerIt.hasNext) { + const polymerSegment = polymerIt.move() + residueIt.setSegment(polymerSegment) + while (residueIt.hasNext) { + const residueSegment = residueIt.move() + const { start, end, index } = residueSegment + if (OrderedSet.areIntersecting(Interval.ofBounds(elements[start], elements[end - 1]), elements)) { + const elementIndex = getElementIndexForAtomRole(model, index, 'trace') + indices.push(elementIndex === -1 ? residueAtomSegments.offsets[index] : elementIndex) + } + } + } + break + case Unit.Kind.Spheres: + case Unit.Kind.Gaussians: + while (polymerIt.hasNext) { + const { start, end } = polymerIt.move() + for (let i = start; i < end; ++i) { indices.push(elements[i]) } + } + break + } + return indices +} + +export namespace PolymerLocationIterator { + export function fromGroup(group: Unit.SymmetryGroup): LocationIterator { + const polymerElementIndices = getPolymerElementIndices(group.units[0]) + const groupCount = polymerElementIndices.length + const instanceCount = group.units.length + const location = StructureElement.create() + const getLocation = (groupIndex: number, instanceIndex: number) => { + const unit = group.units[instanceIndex] + location.unit = unit + location.element = polymerElementIndices[groupIndex] + return location + } + return LocationIterator(groupCount, instanceCount, getLocation) + } +} + export function getPolymerGapCount(unit: Unit) { let count = 0 const { elements } = unit @@ -67,3 +118,29 @@ export function getPolymerGapCount(unit: Unit) { } return count } + +export function getPolymerGapElementIndices(unit: Unit) { + const indices: ElementIndex[] = [] + const polymerGapIt = PolymerGapIterator(unit) + while (polymerGapIt.hasNext) { + const { centerA, centerB } = polymerGapIt.move() + indices.push(centerA.element, centerB.element) + } + return indices +} + +export namespace PolymerGapLocationIterator { + export function fromGroup(group: Unit.SymmetryGroup): LocationIterator { + const polymerGapElementIndices = getPolymerGapElementIndices(group.units[0]) + const groupCount = polymerGapElementIndices.length + const instanceCount = group.units.length + const location = StructureElement.create() + const getLocation = (groupIndex: number, instanceIndex: number) => { + const unit = group.units[instanceIndex] + location.unit = unit + location.element = polymerGapElementIndices[groupIndex] + return location + } + return LocationIterator(groupCount, instanceCount, getLocation) + } +} \ No newline at end of file diff --git a/src/mol-geo/representation/structure/visual/util/polymer/gap-iterator.ts b/src/mol-geo/representation/structure/visual/util/polymer/gap-iterator.ts index 9b91f2894e01ebd89546cee4fafa59514248ee4d..663f10162596a611ff62efc0c4811a5508e99255 100644 --- a/src/mol-geo/representation/structure/visual/util/polymer/gap-iterator.ts +++ b/src/mol-geo/representation/structure/visual/util/polymer/gap-iterator.ts @@ -5,7 +5,6 @@ */ import { Unit, StructureElement, ElementIndex, ResidueIndex } from 'mol-model/structure'; -import { SortedArray } from 'mol-data/int'; import { AtomRole } from 'mol-model/structure/model/types'; import Iterator from 'mol-data/iterator'; import SortedRanges from 'mol-data/int/sorted-ranges'; @@ -40,13 +39,8 @@ export class AtomicPolymerGapIterator implements Iterator<PolymerGapPair> { hasNext: boolean = false; private getElementIndex(residueIndex: ResidueIndex, atomRole: AtomRole) { - const index = getElementIndexForAtomRole(this.unit.model, residueIndex, atomRole) - // TODO handle case when it returns -1 - const elementIndex = SortedArray.indexOf(this.unit.elements, index) as ElementIndex - if (elementIndex === -1) { - console.log('-1', residueIndex, atomRole, index) - } - return elementIndex === -1 ? 0 as ElementIndex : elementIndex + const elementIndex = getElementIndexForAtomRole(this.unit.model, residueIndex, atomRole) + return elementIndex === -1 ? this.unit.model.atomicHierarchy.residueAtomSegments.offsets[residueIndex] : elementIndex } move() { diff --git a/src/mol-geo/util/color-data.ts b/src/mol-geo/util/color-data.ts index e8712bd66db5bceb72554790324f7b6f201222a1..87ea59ccd7dd922f2b0bacb36cf4256e1f2f47c9 100644 --- a/src/mol-geo/util/color-data.ts +++ b/src/mol-geo/util/color-data.ts @@ -96,9 +96,7 @@ export function createGroupColor(locationIt: LocationIterator, color: LocationCo export function createGroupInstanceColor(locationIt: LocationIterator, color: LocationColor, colorData?: ColorData): ColorData { const { groupCount, instanceCount } = locationIt const count = instanceCount * groupCount - console.log(count, instanceCount, groupCount) const colors = colorData && colorData.tColor.ref.value.array.length >= count * 3 ? colorData.tColor.ref.value : createTextureImage(count, 3) - console.log(colors.array.length / 3, count) while (locationIt.hasNext) { const { location, isSecondary, index } = locationIt.move() Color.toArray(color(location, isSecondary), colors.array, index * 3) diff --git a/src/mol-view/theme/color/unit-index.ts b/src/mol-view/theme/color/unit-index.ts index f59d371d8a91d91684e9c88c8c007c6a19ca2dde..2b0231e0d838b92e973cff0f66693bf7bfe67266 100644 --- a/src/mol-view/theme/color/unit-index.ts +++ b/src/mol-view/theme/color/unit-index.ts @@ -20,7 +20,6 @@ export function UnitIndexColorTheme(props: ColorThemeProps): ColorTheme { color = (location: Location): Color => { if (StructureElement.isLocation(location)) { - // console.log(location.unit.id, Unit.findUnitById(location.unit.id, units), units.length, units) return scale.color(Unit.findUnitById(location.unit.id, units)) } else if (Link.isLocation(location)) { return scale.color(Unit.findUnitById(location.aUnit.id, units))