From 27963b5aedd801195aabafc5f7924fe8092e17f0 Mon Sep 17 00:00:00 2001 From: Alexander Rose <alex.rose@rcsb.org> Date: Tue, 13 Aug 2019 14:54:38 -0700 Subject: [PATCH] added option to ignore hydrogens in structure representations --- src/mol-math/geometry/common.ts | 1 + src/mol-math/geometry/gaussian-density/cpu.ts | 4 +- src/mol-math/geometry/gaussian-density/gpu.ts | 4 +- src/mol-math/geometry/molecular-surface.ts | 6 +- .../visual/carbohydrate-link-cylinder.ts | 3 +- .../carbohydrate-terminal-link-cylinder.ts | 3 +- .../visual/cross-link-restraint-cylinder.ts | 3 +- .../structure/visual/element-point.ts | 1 + .../structure/visual/element-sphere.ts | 8 ++- .../visual/gaussian-density-volume.ts | 4 +- .../structure/visual/gaussian-surface-mesh.ts | 6 +- .../visual/gaussian-surface-wireframe.ts | 5 +- .../visual/inter-unit-link-cylinder.ts | 14 ++++- .../visual/intra-unit-link-cylinder.ts | 12 +++- .../visual/molecular-surface-mesh.ts | 8 ++- src/mol-repr/structure/visual/util/common.ts | 62 ++++++++++++++----- src/mol-repr/structure/visual/util/element.ts | 12 +++- .../structure/visual/util/gaussian.ts | 12 ++-- src/mol-repr/structure/visual/util/link.ts | 5 +- .../visual/util/molecular-surface.ts | 13 ++-- 20 files changed, 133 insertions(+), 53 deletions(-) diff --git a/src/mol-math/geometry/common.ts b/src/mol-math/geometry/common.ts index 60fbd3c44..184034082 100644 --- a/src/mol-math/geometry/common.ts +++ b/src/mol-math/geometry/common.ts @@ -14,6 +14,7 @@ export interface PositionData { x: ArrayLike<number>, y: ArrayLike<number>, z: ArrayLike<number>, + id: ArrayLike<number>, /** subset of indices into the x/y/z/radius arrays */ indices: OrderedSet, /** optional element radius */ diff --git a/src/mol-math/geometry/gaussian-density/cpu.ts b/src/mol-math/geometry/gaussian-density/cpu.ts index d1a8c2d16..bb74c6d12 100644 --- a/src/mol-math/geometry/gaussian-density/cpu.ts +++ b/src/mol-math/geometry/gaussian-density/cpu.ts @@ -15,7 +15,7 @@ export async function GaussianDensityCPU(ctx: RuntimeContext, position: Position const { resolution, radiusOffset, smoothness } = props const scaleFactor = 1 / resolution - const { indices, x, y, z } = position + const { indices, x, y, z, id } = position const n = OrderedSet.size(indices) const radii = new Float32Array(n) @@ -100,7 +100,7 @@ export async function GaussianDensityCPU(ctx: RuntimeContext, position: Position data[idx] += dens if (dens > densData[idx]) { densData[idx] = dens - idData[idx] = i + idData[idx] = id[i] } } } diff --git a/src/mol-math/geometry/gaussian-density/gpu.ts b/src/mol-math/geometry/gaussian-density/gpu.ts index 949d5cae7..2128478a6 100644 --- a/src/mol-math/geometry/gaussian-density/gpu.ts +++ b/src/mol-math/geometry/gaussian-density/gpu.ts @@ -224,7 +224,7 @@ function prepareGaussianDensityData(position: PositionData, box: Box3D, radius: const { resolution, radiusOffset } = props const scaleFactor = 1 / resolution - const { indices, x, y, z } = position + const { indices, x, y, z, id } = position const n = OrderedSet.size(indices) const positions = new Float32Array(n * 3) @@ -242,7 +242,7 @@ function prepareGaussianDensityData(position: PositionData, box: Box3D, radius: const r = radius(j) + radiusOffset if (maxRadius < r) maxRadius = r radii[i] = r - groups[i] = i + groups[i] = id[i] } const pad = maxRadius * 2 + resolution * 4 diff --git a/src/mol-math/geometry/molecular-surface.ts b/src/mol-math/geometry/molecular-surface.ts index a133e6704..be6c60127 100644 --- a/src/mol-math/geometry/molecular-surface.ts +++ b/src/mol-math/geometry/molecular-surface.ts @@ -169,7 +169,7 @@ export async function calcMolecularSurface(ctx: RuntimeContext, position: Requir const dd = rad - d if (dd < data[idx]) { data[idx] = dd - idData[idx] = i + idData[idx] = id[i] } } } @@ -282,7 +282,7 @@ export async function calcMolecularSurface(ctx: RuntimeContext, position: Requir // Is this grid point closer to a or b? // Take dot product of atob and gridpoint->p (dx, dy, dz) const dp = dx * atob[0] + dy * atob[1] + dz * atob[2] - idData[idx] = OrderedSet.indexOf(position.indices, dp < 0.0 ? b : a) + idData[idx] = id[OrderedSet.indexOf(position.indices, dp < 0.0 ? b : a)] } } } @@ -323,7 +323,7 @@ export async function calcMolecularSurface(ctx: RuntimeContext, position: Requir const lookup3d = GridLookup3D(position, cellSize) const neighbours = lookup3d.result const box = lookup3d.boundary.box - const { indices, x: px, y: py, z: pz, radius } = position + const { indices, x: px, y: py, z: pz, id, radius } = position const n = OrderedSet.size(indices) const pad = maxRadius * 2 + resolution diff --git a/src/mol-repr/structure/visual/carbohydrate-link-cylinder.ts b/src/mol-repr/structure/visual/carbohydrate-link-cylinder.ts index 094aef3ee..382adbf8f 100644 --- a/src/mol-repr/structure/visual/carbohydrate-link-cylinder.ts +++ b/src/mol-repr/structure/visual/carbohydrate-link-cylinder.ts @@ -42,7 +42,8 @@ function createCarbohydrateLinkCylinderMesh(ctx: VisualContext, structure: Struc location.unit = elements[l.carbohydrateIndexA].unit location.element = elements[l.carbohydrateIndexA].anomericCarbon return theme.size.size(location) * linkSizeFactor - } + }, + ignore: (edgeIndex: number) => false } return createLinkCylinderMesh(ctx, builderProps, props, mesh) diff --git a/src/mol-repr/structure/visual/carbohydrate-terminal-link-cylinder.ts b/src/mol-repr/structure/visual/carbohydrate-terminal-link-cylinder.ts index 460343df6..b0c92d1f7 100644 --- a/src/mol-repr/structure/visual/carbohydrate-terminal-link-cylinder.ts +++ b/src/mol-repr/structure/visual/carbohydrate-terminal-link-cylinder.ts @@ -52,7 +52,8 @@ function createCarbohydrateTerminalLinkCylinderMesh(ctx: VisualContext, structur location.element = l.elementUnit.elements[l.elementIndex] } return theme.size.size(location) * linkSizeFactor - } + }, + ignore: (edgeIndex: number) => false } return createLinkCylinderMesh(ctx, builderProps, props, mesh) diff --git a/src/mol-repr/structure/visual/cross-link-restraint-cylinder.ts b/src/mol-repr/structure/visual/cross-link-restraint-cylinder.ts index 1971a36e4..b215e9e03 100644 --- a/src/mol-repr/structure/visual/cross-link-restraint-cylinder.ts +++ b/src/mol-repr/structure/visual/cross-link-restraint-cylinder.ts @@ -44,7 +44,8 @@ function createCrossLinkRestraintCylinderMesh(ctx: VisualContext, structure: Str location.unit = b.unitA location.element = b.unitA.elements[b.indexA] return theme.size.size(location) * sizeFactor - } + }, + ignore: () => false } return createLinkCylinderMesh(ctx, builderProps, props, mesh) diff --git a/src/mol-repr/structure/visual/element-point.ts b/src/mol-repr/structure/visual/element-point.ts index 1ee303c06..f234613c3 100644 --- a/src/mol-repr/structure/visual/element-point.ts +++ b/src/mol-repr/structure/visual/element-point.ts @@ -19,6 +19,7 @@ export const ElementPointParams = { ...UnitsPointsParams, // sizeFactor: PD.Numeric(1.0, { min: 0, max: 10, step: 0.01 }), pointSizeAttenuation: PD.Boolean(false), + showHydrogens: PD.Boolean(true), } export type ElementPointParams = typeof ElementPointParams diff --git a/src/mol-repr/structure/visual/element-sphere.ts b/src/mol-repr/structure/visual/element-sphere.ts index cffa6ff95..76715a640 100644 --- a/src/mol-repr/structure/visual/element-sphere.ts +++ b/src/mol-repr/structure/visual/element-sphere.ts @@ -16,6 +16,7 @@ export const ElementSphereParams = { ...UnitsSpheresParams, sizeFactor: PD.Numeric(1, { min: 0, max: 10, step: 0.1 }), detail: PD.Numeric(0, { min: 0, max: 3, step: 1 }), + ignoreHydrogens: PD.Boolean(false), } export type ElementSphereParams = typeof ElementSphereParams @@ -31,7 +32,9 @@ export function ElementSphereImpostorVisual(materialId: number): UnitsVisual<Ele getLoci: getElementLoci, eachLocation: eachElement, setUpdateState: (state: VisualUpdateState, newProps: PD.Values<ElementSphereParams>, currentProps: PD.Values<ElementSphereParams>) => { - + state.createGeometry = ( + newProps.ignoreHydrogens !== currentProps.ignoreHydrogens + ) } }, materialId) } @@ -46,7 +49,8 @@ export function ElementSphereMeshVisual(materialId: number): UnitsVisual<Element setUpdateState: (state: VisualUpdateState, newProps: PD.Values<ElementSphereParams>, currentProps: PD.Values<ElementSphereParams>) => { state.createGeometry = ( newProps.sizeFactor !== currentProps.sizeFactor || - newProps.detail !== currentProps.detail + newProps.detail !== currentProps.detail || + newProps.ignoreHydrogens !== currentProps.ignoreHydrogens ) } }, materialId) diff --git a/src/mol-repr/structure/visual/gaussian-density-volume.ts b/src/mol-repr/structure/visual/gaussian-density-volume.ts index 7c49603af..dd12a7b82 100644 --- a/src/mol-repr/structure/visual/gaussian-density-volume.ts +++ b/src/mol-repr/structure/visual/gaussian-density-volume.ts @@ -30,7 +30,8 @@ async function createGaussianDensityVolume(ctx: VisualContext, structure: Struct export const GaussianDensityVolumeParams = { ...ComplexDirectVolumeParams, - ...GaussianDensityTextureParams + ...GaussianDensityTextureParams, + ignoreHydrogens: PD.Boolean(false), } export type GaussianDensityVolumeParams = typeof GaussianDensityVolumeParams @@ -48,6 +49,7 @@ export function GaussianDensityVolumeVisual(materialId: number): ComplexVisual<G state.createGeometry = true newProps.isoValueNorm = Math.exp(-newProps.smoothness) } + if (newProps.ignoreHydrogens !== currentProps.ignoreHydrogens) state.createGeometry = true } }, materialId) } \ No newline at end of file diff --git a/src/mol-repr/structure/visual/gaussian-surface-mesh.ts b/src/mol-repr/structure/visual/gaussian-surface-mesh.ts index f937cedf0..d77e36c94 100644 --- a/src/mol-repr/structure/visual/gaussian-surface-mesh.ts +++ b/src/mol-repr/structure/visual/gaussian-surface-mesh.ts @@ -6,12 +6,11 @@ import { ParamDefinition as PD } from '../../../mol-util/param-definition'; import { UnitsMeshParams, UnitsTextureMeshParams, UnitsVisual, UnitsMeshVisual, UnitsTextureMeshVisual } from '../units-visual'; -import { GaussianDensityParams, computeUnitGaussianDensity, GaussianDensityTextureProps, computeUnitGaussianDensityTexture2d } from './util/gaussian'; +import { GaussianDensityParams, computeUnitGaussianDensity, GaussianDensityTextureProps, computeUnitGaussianDensityTexture2d, GaussianDensityProps } from './util/gaussian'; import { WebGLContext } from '../../../mol-gl/webgl/context'; import { VisualContext } from '../../visual'; import { Unit, Structure } from '../../../mol-model/structure'; import { Theme } from '../../../mol-theme/theme'; -import { GaussianDensityProps } from '../../../mol-math/geometry/gaussian-density'; import { Mesh } from '../../../mol-geo/geometry/mesh/mesh'; import { computeMarchingCubesMesh } from '../../../mol-geo/util/marching-cubes/algorithm'; import { StructureElementIterator, getElementLoci, eachElement } from './util/element'; @@ -26,6 +25,7 @@ export const GaussianSurfaceMeshParams = { ...UnitsMeshParams, ...UnitsTextureMeshParams, ...GaussianDensityParams, + ignoreHydrogens: PD.Boolean(false), } export type GaussianSurfaceMeshParams = typeof GaussianSurfaceMeshParams @@ -64,6 +64,7 @@ export function GaussianSurfaceMeshVisual(materialId: number): UnitsVisual<Gauss if (newProps.radiusOffset !== currentProps.radiusOffset) state.createGeometry = true if (newProps.smoothness !== currentProps.smoothness) state.createGeometry = true if (newProps.useGpu !== currentProps.useGpu) state.createGeometry = true + if (newProps.ignoreHydrogens !== currentProps.ignoreHydrogens) state.createGeometry = true } }, materialId) } @@ -108,6 +109,7 @@ export function GaussianSurfaceTextureMeshVisual(materialId: number): UnitsVisua if (newProps.resolution !== currentProps.resolution) state.createGeometry = true if (newProps.radiusOffset !== currentProps.radiusOffset) state.createGeometry = true if (newProps.smoothness !== currentProps.smoothness) state.createGeometry = true + if (newProps.ignoreHydrogens !== currentProps.ignoreHydrogens) state.createGeometry = true } }, materialId) } \ No newline at end of file diff --git a/src/mol-repr/structure/visual/gaussian-surface-wireframe.ts b/src/mol-repr/structure/visual/gaussian-surface-wireframe.ts index 241f86b8b..bc5b4910f 100644 --- a/src/mol-repr/structure/visual/gaussian-surface-wireframe.ts +++ b/src/mol-repr/structure/visual/gaussian-surface-wireframe.ts @@ -8,9 +8,8 @@ import { ParamDefinition as PD } from '../../../mol-util/param-definition'; import { VisualContext } from '../../visual'; import { Unit, Structure } from '../../../mol-model/structure'; import { Theme } from '../../../mol-theme/theme'; -import { GaussianDensityProps } from '../../../mol-math/geometry/gaussian-density'; import { Lines } from '../../../mol-geo/geometry/lines/lines'; -import { computeUnitGaussianDensity, GaussianDensityParams } from './util/gaussian'; +import { computeUnitGaussianDensity, GaussianDensityParams, GaussianDensityProps } from './util/gaussian'; import { computeMarchingCubesLines } from '../../../mol-geo/util/marching-cubes/algorithm'; import { UnitsLinesParams, UnitsVisual, UnitsLinesVisual } from '../units-visual'; import { StructureElementIterator, getElementLoci, eachElement } from './util/element'; @@ -36,6 +35,7 @@ export const GaussianWireframeParams = { ...UnitsLinesParams, ...GaussianDensityParams, lineSizeAttenuation: PD.Boolean(false), + ignoreHydrogens: PD.Boolean(false), } export type GaussianWireframeParams = typeof GaussianWireframeParams @@ -51,6 +51,7 @@ export function GaussianWireframeVisual(materialId: number): UnitsVisual<Gaussia if (newProps.radiusOffset !== currentProps.radiusOffset) state.createGeometry = true if (newProps.smoothness !== currentProps.smoothness) state.createGeometry = true if (newProps.useGpu !== currentProps.useGpu) state.createGeometry = true + if (newProps.ignoreHydrogens !== currentProps.ignoreHydrogens) state.createGeometry = true } }, materialId) } \ No newline at end of file diff --git a/src/mol-repr/structure/visual/inter-unit-link-cylinder.ts b/src/mol-repr/structure/visual/inter-unit-link-cylinder.ts index 775534ce9..615f29cb4 100644 --- a/src/mol-repr/structure/visual/inter-unit-link-cylinder.ts +++ b/src/mol-repr/structure/visual/inter-unit-link-cylinder.ts @@ -17,11 +17,12 @@ import { VisualUpdateState } from '../../util'; import { PickingId } from '../../../mol-geo/geometry/picking'; import { EmptyLoci, Loci } from '../../../mol-model/loci'; import { Interval, OrderedSet } from '../../../mol-data/int'; +import { isHydrogen } from './util/common'; function createInterUnitLinkCylinderMesh(ctx: VisualContext, structure: Structure, theme: Theme, props: PD.Values<InterUnitLinkParams>, mesh?: Mesh) { const links = structure.links const { bondCount, bonds } = links - const { sizeFactor, sizeAspectRatio } = props + const { sizeFactor, sizeAspectRatio, ignoreHydrogens } = props if (!bondCount) return Mesh.createEmpty(mesh) @@ -43,7 +44,12 @@ function createInterUnitLinkCylinderMesh(ctx: VisualContext, structure: Structur location.unit = b.unitA location.element = b.unitA.elements[b.indexA] return theme.size.size(location) * sizeFactor * sizeAspectRatio - } + }, + ignore: ignoreHydrogens ? (edgeIndex: number) => { + const b = bonds[edgeIndex] + const uA = b.unitA, uB = b.unitB + return isHydrogen(uA, uA.elements[b.indexA]) || isHydrogen(uB, uB.elements[b.indexB]) + } : () => false } return createLinkCylinderMesh(ctx, builderProps, props, mesh) @@ -54,6 +60,7 @@ export const InterUnitLinkParams = { ...LinkCylinderParams, sizeFactor: PD.Numeric(0.3, { min: 0, max: 10, step: 0.01 }), sizeAspectRatio: PD.Numeric(2/3, { min: 0, max: 3, step: 0.01 }), + ignoreHydrogens: PD.Boolean(false), } export type InterUnitLinkParams = typeof InterUnitLinkParams @@ -70,7 +77,8 @@ export function InterUnitLinkVisual(materialId: number): ComplexVisual<InterUnit newProps.sizeAspectRatio !== currentProps.sizeAspectRatio || newProps.radialSegments !== currentProps.radialSegments || newProps.linkScale !== currentProps.linkScale || - newProps.linkSpacing !== currentProps.linkSpacing + newProps.linkSpacing !== currentProps.linkSpacing || + newProps.ignoreHydrogens !== currentProps.ignoreHydrogens ) } }, materialId) diff --git a/src/mol-repr/structure/visual/intra-unit-link-cylinder.ts b/src/mol-repr/structure/visual/intra-unit-link-cylinder.ts index a881695b1..4ead21c95 100644 --- a/src/mol-repr/structure/visual/intra-unit-link-cylinder.ts +++ b/src/mol-repr/structure/visual/intra-unit-link-cylinder.ts @@ -18,6 +18,7 @@ import { VisualUpdateState } from '../../util'; import { PickingId } from '../../../mol-geo/geometry/picking'; import { EmptyLoci, Loci } from '../../../mol-model/loci'; import { Interval, OrderedSet } from '../../../mol-data/int'; +import { isHydrogen } from './util/common'; function createIntraUnitLinkCylinderMesh(ctx: VisualContext, unit: Unit, structure: Structure, theme: Theme, props: PD.Values<IntraUnitLinkParams>, mesh?: Mesh) { if (!Unit.isAtomic(unit)) return Mesh.createEmpty(mesh) @@ -28,7 +29,7 @@ function createIntraUnitLinkCylinderMesh(ctx: VisualContext, unit: Unit, structu const links = unit.links const { edgeCount, a, b, edgeProps, offset } = links const { order: _order, flags: _flags } = edgeProps - const { sizeFactor, sizeAspectRatio } = props + const { sizeFactor, sizeAspectRatio, ignoreHydrogens } = props if (!edgeCount) return Mesh.createEmpty(mesh) @@ -63,7 +64,10 @@ function createIntraUnitLinkCylinderMesh(ctx: VisualContext, unit: Unit, structu radius: (edgeIndex: number) => { location.element = elements[a[edgeIndex]] return theme.size.size(location) * sizeFactor * sizeAspectRatio - } + }, + ignore: ignoreHydrogens ? (edgeIndex: number) => { + return isHydrogen(unit, elements[a[edgeIndex]]) || isHydrogen(unit, elements[b[edgeIndex]]) + } : () => false } return createLinkCylinderMesh(ctx, builderProps, props, mesh) @@ -74,6 +78,7 @@ export const IntraUnitLinkParams = { ...LinkCylinderParams, sizeFactor: PD.Numeric(0.3, { min: 0, max: 10, step: 0.01 }), sizeAspectRatio: PD.Numeric(2/3, { min: 0, max: 3, step: 0.01 }), + ignoreHydrogens: PD.Boolean(false), } export type IntraUnitLinkParams = typeof IntraUnitLinkParams @@ -90,7 +95,8 @@ export function IntraUnitLinkVisual(materialId: number): UnitsVisual<IntraUnitLi newProps.sizeAspectRatio !== currentProps.sizeAspectRatio || newProps.radialSegments !== currentProps.radialSegments || newProps.linkScale !== currentProps.linkScale || - newProps.linkSpacing !== currentProps.linkSpacing + newProps.linkSpacing !== currentProps.linkSpacing || + newProps.ignoreHydrogens !== currentProps.ignoreHydrogens ) } }, materialId) diff --git a/src/mol-repr/structure/visual/molecular-surface-mesh.ts b/src/mol-repr/structure/visual/molecular-surface-mesh.ts index 2aa8c863e..cba0730ac 100644 --- a/src/mol-repr/structure/visual/molecular-surface-mesh.ts +++ b/src/mol-repr/structure/visual/molecular-surface-mesh.ts @@ -6,12 +6,12 @@ import { ParamDefinition as PD } from '../../../mol-util/param-definition'; import { UnitsMeshParams, UnitsTextureMeshParams, UnitsVisual, UnitsMeshVisual } from '../units-visual'; -import { MolecularSurfaceCalculationParams, MolecularSurfaceCalculationProps } from '../../../mol-math/geometry/molecular-surface'; +import { MolecularSurfaceCalculationParams } from '../../../mol-math/geometry/molecular-surface'; import { VisualContext } from '../../visual'; import { Unit, Structure } from '../../../mol-model/structure'; import { Theme } from '../../../mol-theme/theme'; import { Mesh } from '../../../mol-geo/geometry/mesh/mesh'; -import { computeUnitMolecularSurface } from './util/molecular-surface'; +import { computeUnitMolecularSurface, MolecularSurfaceProps } from './util/molecular-surface'; import { computeMarchingCubesMesh } from '../../../mol-geo/util/marching-cubes/algorithm'; import { StructureElementIterator, getElementLoci, eachElement } from './util/element'; import { VisualUpdateState } from '../../util'; @@ -20,12 +20,13 @@ export const MolecularSurfaceMeshParams = { ...UnitsMeshParams, ...UnitsTextureMeshParams, ...MolecularSurfaceCalculationParams, + ignoreHydrogens: PD.Boolean(false), } export type MolecularSurfaceMeshParams = typeof MolecularSurfaceMeshParams // -async function createMolecularSurfaceMesh(ctx: VisualContext, unit: Unit, structure: Structure, theme: Theme, props: MolecularSurfaceCalculationProps, mesh?: Mesh): Promise<Mesh> { +async function createMolecularSurfaceMesh(ctx: VisualContext, unit: Unit, structure: Structure, theme: Theme, props: MolecularSurfaceProps, mesh?: Mesh): Promise<Mesh> { const { transform, field, idField } = await computeUnitMolecularSurface(unit, props).runInContext(ctx.runtime) const params = { @@ -52,6 +53,7 @@ export function MolecularSurfaceMeshVisual(materialId: number): UnitsVisual<Mole if (newProps.resolution !== currentProps.resolution) state.createGeometry = true if (newProps.probeRadius !== currentProps.probeRadius) state.createGeometry = true if (newProps.probePositions !== currentProps.probePositions) state.createGeometry = true + if (newProps.ignoreHydrogens !== currentProps.ignoreHydrogens) state.createGeometry = true } }, materialId) } \ No newline at end of file diff --git a/src/mol-repr/structure/visual/util/common.ts b/src/mol-repr/structure/visual/util/common.ts index de52db7f5..33d909faf 100644 --- a/src/mol-repr/structure/visual/util/common.ts +++ b/src/mol-repr/structure/visual/util/common.ts @@ -10,6 +10,8 @@ import { TransformData, createTransform } from '../../../../mol-geo/geometry/tra import { OrderedSet, SortedArray } from '../../../../mol-data/int'; import { EmptyLoci, Loci } from '../../../../mol-model/loci'; import { PhysicalSizeTheme } from '../../../../mol-theme/size/physical'; +import { AtomicNumbers, AtomNumber } from '../../../../mol-model/structure/model/properties/atomic'; +import { fillSerial } from '../../../../mol-util/array'; /** Return a Loci for the elements of a whole residue the elementIndex belongs to. */ export function getResidueLoci(structure: Structure, unit: Unit.Atomic, elementIndex: ElementIndex): Loci { @@ -95,14 +97,34 @@ export function getConformation(unit: Unit) { } } -export function getUnitConformationAndRadius(unit: Unit) { +export function getUnitConformationAndRadius(unit: Unit, ignoreHydrogens = false) { const conformation = getConformation(unit) const { elements } = unit + + let indices: SortedArray<ElementIndex> + let id: ArrayLike<number> + + if (ignoreHydrogens) { + const _indices = [] + const _id = [] + for (let i = 0, il = elements.length; i < il; ++i) { + if (isHydrogen(unit, elements[i])) continue + _indices.push(elements[i]) + _id.push(i) + } + indices = SortedArray.ofSortedArray(_indices) + id = _id + } else { + indices = elements + id = fillSerial(new Uint32Array(indices.length)) + } + const position = { - indices: elements, + indices, x: conformation.x, y: conformation.y, - z: conformation.z + z: conformation.z, + id } const l = StructureElement.create(unit) @@ -115,13 +137,12 @@ export function getUnitConformationAndRadius(unit: Unit) { return { position, radius } } -export function getStructureConformationAndRadius(structure: Structure) { - const n = structure.elementCount - - const xs = new Float32Array(n) - const ys = new Float32Array(n) - const zs = new Float32Array(n) - const rs = new Float32Array(n) +export function getStructureConformationAndRadius(structure: Structure, ignoreHydrogens = false) { + const xs: number[] = [] + const ys: number[] = [] + const zs: number[] = [] + const rs: number[] = [] + const id: number[] = [] const l = StructureElement.create() const sizeTheme = PhysicalSizeTheme({}, {}) @@ -134,17 +155,28 @@ export function getStructureConformationAndRadius(structure: Structure) { l.unit = unit for (let j = 0, jl = elements.length; j < jl; ++j) { const eI = elements[j] - xs[m + j] = x(eI) - ys[m + j] = y(eI) - zs[m + j] = z(eI) + if (ignoreHydrogens && isHydrogen(unit, eI)) continue + + const mj = m + j + xs[mj] = x(eI) + ys[mj] = y(eI) + zs[mj] = z(eI) l.element = eI - rs[m + j] = sizeTheme.size(l) + rs[mj] = sizeTheme.size(l) + id[mj] = mj } m += elements.length } - const position = { indices: OrderedSet.ofRange(0, n), x: xs, y: ys, z: zs } + const position = { indices: OrderedSet.ofRange(0, m), x: xs, y: ys, z: zs, id } const radius = (index: number) => rs[index] return { position, radius } +} + +const _H = AtomicNumbers['H'] +export function isHydrogen(unit: Unit, element: ElementIndex) { + if (Unit.isCoarse(unit)) return false + if (AtomNumber(unit.model.atomicHierarchy.atoms.type_symbol.value(element)) === _H) return true + return false } \ No newline at end of file diff --git a/src/mol-repr/structure/visual/util/element.ts b/src/mol-repr/structure/visual/util/element.ts index d70dc06a3..25f536c9a 100644 --- a/src/mol-repr/structure/visual/util/element.ts +++ b/src/mol-repr/structure/visual/util/element.ts @@ -19,10 +19,12 @@ import { Theme } from '../../../../mol-theme/theme'; import { StructureGroup } from '../../../../mol-repr/structure/units-visual'; import { Spheres } from '../../../../mol-geo/geometry/spheres/spheres'; import { SpheresBuilder } from '../../../../mol-geo/geometry/spheres/spheres-builder'; +import { isHydrogen } from './common'; export interface ElementSphereMeshProps { detail: number, - sizeFactor: number + sizeFactor: number, + ignoreHydrogens: boolean, } export function createElementSphereMesh(ctx: VisualContext, unit: Unit, structure: Structure, theme: Theme, props: ElementSphereMeshProps, mesh?: Mesh): Mesh { @@ -39,6 +41,8 @@ export function createElementSphereMesh(ctx: VisualContext, unit: Unit, structur l.unit = unit for (let i = 0; i < elementCount; i++) { + if (props.ignoreHydrogens && isHydrogen(unit, elements[i])) continue + l.element = elements[i] pos(elements[i], v) @@ -49,7 +53,9 @@ export function createElementSphereMesh(ctx: VisualContext, unit: Unit, structur return MeshBuilder.getMesh(builderState) } -export interface ElementSphereImpostorProps { } +export interface ElementSphereImpostorProps { + ignoreHydrogens: boolean, +} export function createElementSphereImpostor(ctx: VisualContext, unit: Unit, structure: Structure, theme: Theme, props: ElementSphereImpostorProps, spheres?: Spheres): Spheres { @@ -61,6 +67,8 @@ export function createElementSphereImpostor(ctx: VisualContext, unit: Unit, stru const pos = unit.conformation.invariantPosition for (let i = 0; i < elementCount; i++) { + if (props.ignoreHydrogens && isHydrogen(unit, elements[i])) continue + pos(elements[i], v) builder.add(v[0], v[1], v[2], i) } diff --git a/src/mol-repr/structure/visual/util/gaussian.ts b/src/mol-repr/structure/visual/util/gaussian.ts index 401e68a60..fb8509759 100644 --- a/src/mol-repr/structure/visual/util/gaussian.ts +++ b/src/mol-repr/structure/visual/util/gaussian.ts @@ -18,6 +18,7 @@ export const GaussianDensityParams = { radiusOffset: PD.Numeric(0, { min: 0, max: 10, step: 0.1 }), smoothness: PD.Numeric(1.5, { min: 0.5, max: 2.5, step: 0.1 }), useGpu: PD.Boolean(false), + ignoreHydrogens: PD.Boolean(false), } export const DefaultGaussianDensityProps = PD.getDefaultValues(GaussianDensityParams) export type GaussianDensityProps = typeof DefaultGaussianDensityProps @@ -26,6 +27,7 @@ export const GaussianDensityTextureParams = { resolution: PD.Numeric(1, { min: 0.1, max: 20, step: 0.1 }), radiusOffset: PD.Numeric(0, { min: 0, max: 10, step: 0.1 }), smoothness: PD.Numeric(1.5, { min: 0.5, max: 2.5, step: 0.1 }), + ignoreHydrogens: PD.Boolean(false), } export const DefaultGaussianDensityTextureProps = PD.getDefaultValues(GaussianDensityTextureParams) export type GaussianDensityTextureProps = typeof DefaultGaussianDensityTextureProps @@ -33,21 +35,21 @@ export type GaussianDensityTextureProps = typeof DefaultGaussianDensityTexturePr // export function computeUnitGaussianDensity(unit: Unit, props: GaussianDensityProps, webgl?: WebGLContext) { - const { position, radius } = getUnitConformationAndRadius(unit) + const { position, radius } = getUnitConformationAndRadius(unit, props.ignoreHydrogens) return Task.create('Gaussian Density', async ctx => { return await GaussianDensity(ctx, position, unit.lookup3d.boundary.box, radius, props, webgl); }); } export function computeUnitGaussianDensityTexture(unit: Unit, props: GaussianDensityTextureProps, webgl: WebGLContext, texture?: Texture) { - const { position, radius } = getUnitConformationAndRadius(unit) + const { position, radius } = getUnitConformationAndRadius(unit, props.ignoreHydrogens) return Task.create('Gaussian Density', async ctx => { return GaussianDensityTexture(webgl, position, unit.lookup3d.boundary.box, radius, props, texture); }); } export function computeUnitGaussianDensityTexture2d(unit: Unit, props: GaussianDensityTextureProps, webgl: WebGLContext, texture?: Texture) { - const { position, radius } = getUnitConformationAndRadius(unit) + const { position, radius } = getUnitConformationAndRadius(unit, props.ignoreHydrogens) return Task.create('Gaussian Density', async ctx => { return GaussianDensityTexture2d(webgl, position, unit.lookup3d.boundary.box, radius, props, texture); }); @@ -56,14 +58,14 @@ export function computeUnitGaussianDensityTexture2d(unit: Unit, props: GaussianD // export function computeStructureGaussianDensity(structure: Structure, props: GaussianDensityProps, webgl?: WebGLContext) { - const { position, radius } = getStructureConformationAndRadius(structure) + const { position, radius } = getStructureConformationAndRadius(structure, props.ignoreHydrogens) return Task.create('Gaussian Density', async ctx => { return await GaussianDensity(ctx, position, structure.lookup3d.boundary.box, radius, props, webgl); }); } export function computeStructureGaussianDensityTexture(structure: Structure, props: GaussianDensityTextureProps, webgl: WebGLContext, texture?: Texture) { - const { position, radius } = getStructureConformationAndRadius(structure) + const { position, radius } = getStructureConformationAndRadius(structure, props.ignoreHydrogens) return Task.create('Gaussian Density', async ctx => { return GaussianDensityTexture(webgl, position, structure.lookup3d.boundary.box, radius, props, texture); }); diff --git a/src/mol-repr/structure/visual/util/link.ts b/src/mol-repr/structure/visual/util/link.ts index 0952cd022..69079b62e 100644 --- a/src/mol-repr/structure/visual/util/link.ts +++ b/src/mol-repr/structure/visual/util/link.ts @@ -59,6 +59,7 @@ export interface LinkCylinderMeshBuilderProps { order(edgeIndex: number): number flags(edgeIndex: number): LinkType radius(edgeIndex: number): number + ignore(edgeIndex: number): boolean } /** @@ -66,7 +67,7 @@ export interface LinkCylinderMeshBuilderProps { * the half closer to the first vertex, i.e. vertex a. */ export function createLinkCylinderMesh(ctx: VisualContext, linkBuilder: LinkCylinderMeshBuilderProps, props: LinkCylinderProps, mesh?: Mesh) { - const { linkCount, referencePosition, position, order, flags, radius } = linkBuilder + const { linkCount, referencePosition, position, order, flags, radius, ignore } = linkBuilder if (!linkCount) return Mesh.createEmpty(mesh) @@ -87,6 +88,8 @@ export function createLinkCylinderMesh(ctx: VisualContext, linkBuilder: LinkCyli } for (let edgeIndex = 0, _eI = linkCount; edgeIndex < _eI; ++edgeIndex) { + if (ignore(edgeIndex)) continue + position(va, vb, edgeIndex) const linkRadius = radius(edgeIndex) diff --git a/src/mol-repr/structure/visual/util/molecular-surface.ts b/src/mol-repr/structure/visual/util/molecular-surface.ts index 4444ec061..5d3fd7491 100644 --- a/src/mol-repr/structure/visual/util/molecular-surface.ts +++ b/src/mol-repr/structure/visual/util/molecular-surface.ts @@ -11,8 +11,13 @@ import { PositionData, DensityData } from '../../../../mol-math/geometry'; import { MolecularSurfaceCalculationProps, calcMolecularSurface } from '../../../../mol-math/geometry/molecular-surface'; import { OrderedSet } from '../../../../mol-data/int'; -function getPositionDataAndMaxRadius(unit: Unit, props: MolecularSurfaceCalculationProps) { - const { position, radius } = getUnitConformationAndRadius(unit) +export type MolecularSurfaceProps = MolecularSurfaceCalculationProps & { + ignoreHydrogens: boolean +} + +function getPositionDataAndMaxRadius(unit: Unit, props: MolecularSurfaceProps) { + const { probeRadius, ignoreHydrogens } = props + const { position, radius } = getUnitConformationAndRadius(unit, ignoreHydrogens) const { indices } = position const n = OrderedSet.size(indices) const radii = new Float32Array(OrderedSet.end(indices)) @@ -22,13 +27,13 @@ function getPositionDataAndMaxRadius(unit: Unit, props: MolecularSurfaceCalculat const j = OrderedSet.getAt(indices, i) const r = radius(j) if (maxRadius < r) maxRadius = r - radii[j] = r + props.probeRadius + radii[j] = r + probeRadius } return { position: { ...position, radius: radii }, maxRadius } } -export function computeUnitMolecularSurface(unit: Unit, props: MolecularSurfaceCalculationProps) { +export function computeUnitMolecularSurface(unit: Unit, props: MolecularSurfaceProps) { const { position, maxRadius } = getPositionDataAndMaxRadius(unit, props) return Task.create('Molecular Surface', async ctx => { return await MolecularSurface(ctx, position, maxRadius, props); -- GitLab