diff --git a/src/apps/render-test/state.ts b/src/apps/render-test/state.ts index c2616d4970b52d6ac0dbe104494fa3072915b4b1..1682f2ed840c6543a2cf094dc2a737509d339d4e 100644 --- a/src/apps/render-test/state.ts +++ b/src/apps/render-test/state.ts @@ -17,10 +17,10 @@ import Spacefill, { SpacefillProps } from 'mol-geo/representation/structure/spac import Point, { PointProps } from 'mol-geo/representation/structure/point' import { Run } from 'mol-task' -import { Symmetry, Structure } from 'mol-model/structure' +import { Symmetry, Structure, Model } from 'mol-model/structure' // import mcubes from './utils/mcubes' -import { getStructuresFromPdbId, getStructuresFromFile, log } from './utils' +import { getModelFromPdbId, getModelFromFile, log } from './utils' import { StructureRepresentation } from 'mol-geo/representation/structure'; import { Color } from 'mol-util/color'; // import Cylinder from 'mol-geo/primitive/cylinder'; @@ -87,18 +87,24 @@ export default class State { this.viewer.animate() } - async initStructure (structure: Structure) { + async initStructure (model: Model) { const { viewer, loading } = this viewer.clear() - const struct = await Run(Symmetry.buildAssembly(structure, '1'), log, 100) + let structure: Structure + const assemblies = model.symmetry.assemblies + if (assemblies.length) { + structure = await Run(Symmetry.buildAssembly(Structure.ofModel(model), '1'), log, 100) + } else { + structure = Structure.ofModel(model) + } this.pointRepr = StructureRepresentation(Point) - await Run(this.pointRepr.create(struct, this.getPointProps()), log, 100) + await Run(this.pointRepr.create(structure, this.getPointProps()), log, 100) viewer.add(this.pointRepr) this.spacefillRepr = StructureRepresentation(Spacefill) - await Run(this.spacefillRepr.create(struct, this.getSpacefillProps()), log, 100) + await Run(this.spacefillRepr.create(structure, this.getSpacefillProps()), log, 100) viewer.add(this.spacefillRepr) this.updateVisibility() @@ -112,7 +118,7 @@ export default class State { this.viewer.clear() this.loading.next(true) - const structures = await getStructuresFromFile(file) + const structures = await getModelFromFile(file) this.initStructure(structures[0]) } @@ -121,7 +127,7 @@ export default class State { if (this.pdbId.length !== 4) return this.loading.next(true) - const structures = await getStructuresFromPdbId(this.pdbId) + const structures = await getModelFromPdbId(this.pdbId) this.initStructure(structures[0]) } @@ -154,87 +160,4 @@ export default class State { } this.viewer.requestDraw() } -} - - - -// async foo () { -// const p1 = Vec3.create(0, 4, 0) -// const p2 = Vec3.create(-3, 0, 0) - -// // const position = ValueCell.create(new Float32Array([0, -1, 0, -1, 0, 0, 1, 1, 0])) -// // const normal = ValueCell.create(new Float32Array([0, 0, 0, 0, 0, 0, 0, 0, 0])) - -// const transformArray1 = ValueCell.create(new Float32Array(16)) -// const transformArray2 = ValueCell.create(new Float32Array(16 * 3)) -// const m4 = Mat4.identity() -// Mat4.toArray(m4, transformArray1.ref.value, 0) -// Mat4.toArray(m4, transformArray2.ref.value, 0) -// Mat4.setTranslation(m4, p1) -// Mat4.toArray(m4, transformArray2.ref.value, 16) -// Mat4.setTranslation(m4, p2) -// Mat4.toArray(m4, transformArray2.ref.value, 32) - -// const color = ValueCell.create(createColorTexture(3)) -// color.ref.value.set([ -// 0, 0, 255, -// 0, 255, 0, -// 255, 0, 0 -// ]) - -// // const points = createRenderObject('point', { -// // position, -// // transform: transformArray1 -// // }) -// // // renderer.add(points) - -// // const mesh = createRenderObject('mesh', { -// // position, -// // normal, -// // color, -// // transform: transformArray2 -// // }) -// // renderer.add(mesh) - -// // const cylinder = Cylinder({ height: 3, radiusBottom: 0.5, radiusTop: 0.5 }) -// // console.log(cylinder) -// // const cylinderMesh = createRenderObject('mesh', { -// // position: ValueCell.create(cylinder.vertices), -// // normal: ValueCell.create(cylinder.normals), -// // color, -// // transform: transformArray2 -// // }, cylinder.indices) -// // renderer.add(cylinderMesh) - -// // const sphere = Icosahedron() -// // console.log(sphere) - -// // const box = Box() -// // console.log(box) - -// // const points2 = createRenderObject('point', { -// // position: ValueCell.create(new Float32Array(box.vertices)), -// // transform: transformArray1 -// // }) -// // renderer.add(points2) - -// // let rr = 0.7; -// // function cubesF(x: number, y: number, z: number) { -// // return x * x + y * y + z * z - rr * rr; -// // } -// // let cubes = await mcubes(cubesF); - -// // const makeCubesMesh = () => createRenderObject('mesh', { -// // position: cubes.surface.vertexBuffer, -// // normal: cubes.surface.normalBuffer, -// // color, -// // transform: transformArray2, -// // elements: cubes.surface.indexBuffer, - -// // instanceCount: transformArray2.ref.value.length / 16, -// // elementCount: cubes.surface.triangleCount, -// // positionCount: cubes.surface.vertexCount -// // }, {}); -// // const mesh2 = makeCubesMesh(); -// // renderer.add(mesh2) -// } \ No newline at end of file +} \ No newline at end of file diff --git a/src/apps/render-test/utils/index.ts b/src/apps/render-test/utils/index.ts index 738bd7851a542c6522ccd07cb869a73e11ee6891..3225ea529bb68181355139fea35389f62fce238d 100644 --- a/src/apps/render-test/utils/index.ts +++ b/src/apps/render-test/utils/index.ts @@ -6,7 +6,7 @@ import CIF from 'mol-io/reader/cif' import { Run, Progress } from 'mol-task' -import { Structure } from 'mol-model/structure' +import { Model } from 'mol-model/structure' export function log(progress: Progress) { const p = progress.root.progress @@ -20,10 +20,10 @@ export async function parseCif(data: string|Uint8Array) { return parsed } -export async function getStructuresFromPdbId(pdbid: string) { +export async function getModelFromPdbId(pdbid: string) { const data = await fetch(`https://files.rcsb.org/download/${pdbid}.cif`) const parsed = await parseCif(await data.text()) - return Structure.ofData({ kind: 'mmCIF', data: CIF.schema.mmCIF(parsed.result.blocks[0]) }) + return Model.create({ kind: 'mmCIF', data: CIF.schema.mmCIF(parsed.result.blocks[0]) }) } const readFileAsText = (file: File) => { @@ -38,7 +38,7 @@ const readFileAsText = (file: File) => { }) } -export async function getStructuresFromFile(file: File) { +export async function getModelFromFile(file: File) { const parsed = await parseCif(await readFileAsText(file)) - return Structure.ofData({ kind: 'mmCIF', data: CIF.schema.mmCIF(parsed.result.blocks[0]) }) + return Model.create({ kind: 'mmCIF', data: CIF.schema.mmCIF(parsed.result.blocks[0]) }) } \ No newline at end of file diff --git a/src/mol-geo/representation/structure/spacefill.ts b/src/mol-geo/representation/structure/spacefill.ts index 6f994adee431d2f060fd375b62031bf9d47a67b0..4e2f9168361a547201b789eb28fdbddc9b66309b 100644 --- a/src/mol-geo/representation/structure/spacefill.ts +++ b/src/mol-geo/representation/structure/spacefill.ts @@ -18,6 +18,7 @@ import { VdwRadius } from 'mol-model/structure/model/properties/atomic'; import { createTransforms, createColors } from './utils'; import { ColorTheme } from '../../theme'; import VertexMap from '../../shape/vertex-map'; +import CoarseGrained from 'mol-model/structure/model/properties/coarse-grained'; export const DefaultSpacefillProps = { detail: 0, @@ -25,9 +26,9 @@ export const DefaultSpacefillProps = { } export type SpacefillProps = Partial<typeof DefaultSpacefillProps> -function createSpacefillMesh(unit: Unit, elementGroup: ElementGroup, detail: number) { - return Task.create('Spacefill', async ctx => { - const meshBuilder = MeshBuilder.create() +function buildAtomSpheres(meshBuilder: MeshBuilder, unit: Unit, elementGroup: ElementGroup, detail: number) { + return Task.create('Atom spheres', async ctx => { + if (!Unit.isAtomic(unit)) return const v = Vec3.zero() const m = Mat4.identity() @@ -43,15 +44,54 @@ function createSpacefillMesh(unit: Unit, elementGroup: ElementGroup, detail: num Mat4.setTranslation(m, v) meshBuilder.setId(i) - meshBuilder.addIcosahedron(m, { - radius: VdwRadius(type_symbol.value(e)), - detail - }) + meshBuilder.addIcosahedron(m, { radius: VdwRadius(type_symbol.value(e)), detail }) + + if (i % 10000 === 0 && ctx.shouldUpdate) { + await ctx.update({ message: 'Atom spheres', current: i, max: elementCount }); + } + } + }) +} + +function buildCoarseSpheres(meshBuilder: MeshBuilder, unit: Unit, elementGroup: ElementGroup, detail: number) { + return Task.create('Coarse spheres', async ctx => { + if (!Unit.isCoarse(unit) || unit.elementType !== CoarseGrained.ElementType.Sphere) return + + const v = Vec3.zero() + const m = Mat4.identity() + + const { x, y, z, radius } = unit.model.coarseGrained.spheres + const elementCount = OrderedSet.size(elementGroup.elements) + console.log('building coarse spheres', elementCount) + for (let i = 0; i < elementCount; i++) { + const e = OrderedSet.getAt(elementGroup.elements, i) + v[0] = x[e] + v[1] = y[e] + v[2] = z[e] + Mat4.setTranslation(m, v) + + meshBuilder.setId(i) + meshBuilder.addIcosahedron(m, { radius: radius.value(e), detail }) if (i % 10000 === 0 && ctx.shouldUpdate) { - await ctx.update({ message: 'Spacefill', current: i, max: elementCount }); + await ctx.update({ message: 'Coarse spheres', current: i, max: elementCount }); } } + }) +} + +function createSpacefillMesh(unit: Unit, elementGroup: ElementGroup, detail: number) { + return Task.create('Spacefill', async ctx => { + const meshBuilder = MeshBuilder.create() + + if (Unit.isAtomic(unit)) { + await ctx.runChild(buildAtomSpheres(meshBuilder, unit, elementGroup, detail)) + } + + if (Unit.isCoarse(unit) && unit.elementType === CoarseGrained.ElementType.Sphere) { + console.log('building coarse spheres') + await ctx.runChild(buildCoarseSpheres(meshBuilder, unit, elementGroup, detail)) + } return meshBuilder.getMesh() }) diff --git a/src/mol-geo/representation/structure/utils.ts b/src/mol-geo/representation/structure/utils.ts index a7a1d158781faa97ca8f3100319e74b4b2a05c0b..65f7b35962d4b6eb769b8d34de2d4ff3ece77f59 100644 --- a/src/mol-geo/representation/structure/utils.ts +++ b/src/mol-geo/representation/structure/utils.ts @@ -12,7 +12,7 @@ import { createUniformSize } from '../../util/size-data'; import { vdwSizeData } from '../../theme/structure/size/vdw'; import VertexMap from '../../shape/vertex-map'; import { ColorTheme, SizeTheme } from '../../theme'; -import { atomIndexColorData, elementSymbolColorData, instanceIndexColorData, chainIdColorData } from '../../theme/structure/color'; +import { elementIndexColorData, elementSymbolColorData, instanceIndexColorData, chainIdColorData } from '../../theme/structure/color'; export function createTransforms(units: ReadonlyArray<Unit>) { const unitCount = units.length @@ -26,7 +26,7 @@ export function createTransforms(units: ReadonlyArray<Unit>) { export function createColors(units: ReadonlyArray<Unit>, elementGroup: ElementGroup, vertexMap: VertexMap, props: ColorTheme) { switch (props.name) { case 'atom-index': - return atomIndexColorData({ units, elementGroup, vertexMap }) + return elementIndexColorData({ units, elementGroup, vertexMap }) case 'chain-id': return chainIdColorData({ units, elementGroup, vertexMap }) case 'element-symbol': diff --git a/src/mol-geo/theme/structure/color/chain-id.ts b/src/mol-geo/theme/structure/color/chain-id.ts index a6bd36b1aad179b0f1ac8269c47fcaa357994a53..43dfc0db654e236eaf9af30e8ed49b16d033d5be 100644 --- a/src/mol-geo/theme/structure/color/chain-id.ts +++ b/src/mol-geo/theme/structure/color/chain-id.ts @@ -4,21 +4,32 @@ * @author Alexander Rose <alexander.rose@weirdbyte.de> */ -import { ElementGroup, Model } from 'mol-model/structure'; +import { ElementGroup, Unit, Queries, Element } from 'mol-model/structure'; import { StructureColorDataProps } from '.'; import { createAttributeOrElementColor } from '../../../util/color-data'; import { ColorScale } from 'mol-util/color'; +import { Column } from 'mol-data/db'; -function createChainIdMap(model: Model) { - const { chains } = model.hierarchy - const { label_asym_id } = chains - +function createChainIdMap(unit: Unit) { const map = new Map<string, number>() let index = 0 - for (let i = 0, il = chains._rowCount; i < il; ++i) { - const chainId = label_asym_id.value(i) + let count: number + let asym_id: Column<string> + if (Unit.isAtomic(unit)) { + asym_id = unit.hierarchy.chains.label_asym_id + count = unit.hierarchy.chains._rowCount + } else if (Unit.isCoarse(unit)) { + asym_id = unit.siteBases.asym_id + count = unit.siteBases.count + } else { + console.warn('Unknown unit type') + return { map, count: index } + } + + for (let i = 0; i < count; ++i) { + const chainId = asym_id.value(i) if (map.get(chainId) === undefined) { map.set(chainId, index) index += 1 @@ -31,20 +42,25 @@ export function chainIdColorData(props: StructureColorDataProps) { const { units, elementGroup, vertexMap } = props const unit = units[0] - const { chains, chainSegments } = unit.model.hierarchy - const { label_asym_id } = chains - const { map, count } = createChainIdMap(unit.model) + const { map, count } = createChainIdMap(unit) const domain = [ 0, count - 1 ] const scale = ColorScale.create({ domain }) + let asym_id: Element.Property<string> + if (Unit.isAtomic(unit)) { + asym_id = Queries.props.chain.label_asym_id + } else if (Unit.isCoarse(unit)) { + asym_id = Queries.props.coarse_grained.asym_id + } + + const l = Element.Location() + l.unit = unit + return createAttributeOrElementColor(vertexMap, { colorFn: (elementIdx: number) => { - const aI = ElementGroup.getAt(elementGroup, elementIdx); - const cI = chainSegments.segmentMap[aI] - const chainId = label_asym_id.value(cI) - - return scale.color(map.get(chainId) || 0) + l.element = ElementGroup.getAt(elementGroup, elementIdx) + return scale.color(map.get(asym_id(l)) || 0) }, vertexMap }) diff --git a/src/mol-geo/theme/structure/color/atom-index.ts b/src/mol-geo/theme/structure/color/element-index.ts similarity index 91% rename from src/mol-geo/theme/structure/color/atom-index.ts rename to src/mol-geo/theme/structure/color/element-index.ts index 1bd61c99a132c2a85b027b3cbcb7c1fdb189be2b..b205043d46ffb5a1fee65485dc9f026644f7a2c6 100644 --- a/src/mol-geo/theme/structure/color/atom-index.ts +++ b/src/mol-geo/theme/structure/color/element-index.ts @@ -9,7 +9,7 @@ import { StructureColorDataProps } from '.'; import { OrderedSet } from 'mol-data/int'; import { createElementInstanceColor } from '../../../util/color-data'; -export function atomIndexColorData(props: StructureColorDataProps) { +export function elementIndexColorData(props: StructureColorDataProps) { const { units, elementGroup, vertexMap } = props const instanceCount = units.length const elementCount = OrderedSet.size(elementGroup.elements) diff --git a/src/mol-geo/theme/structure/color/index.ts b/src/mol-geo/theme/structure/color/index.ts index 435874109499156465610b627b86287d4f2d6b6c..82d5b22a6c6535744d2c1000f5d0948bdace8311 100644 --- a/src/mol-geo/theme/structure/color/index.ts +++ b/src/mol-geo/theme/structure/color/index.ts @@ -13,7 +13,7 @@ export interface StructureColorDataProps { vertexMap: VertexMap } -export { atomIndexColorData } from './atom-index' +export { elementIndexColorData } from './element-index' export { chainIdColorData } from './chain-id' export { elementSymbolColorData } from './element-symbol' export { instanceIndexColorData } from './instance-index' \ No newline at end of file diff --git a/src/mol-view/viewer.ts b/src/mol-view/viewer.ts index 0a0f42a580bf9e2b7774b8fc251b2db4b8d49a91..7fef68f8545115e60d9cc8c39910d5050426c9f7 100644 --- a/src/mol-view/viewer.ts +++ b/src/mol-view/viewer.ts @@ -55,7 +55,7 @@ namespace Viewer { input.resize.subscribe(handleResize) const camera = PerspectiveCamera.create({ - near: 0.01, + near: 0.1, far: 10000, position: Vec3.create(0, 0, 50) })