diff --git a/src/mol-geo/primitive/prism.ts b/src/mol-geo/primitive/prism.ts index 22f12872e9490c7b792a3c0c5efd80e77765d755..f019a5bef2e63f29618b125229bd2213282f321e 100644 --- a/src/mol-geo/primitive/prism.ts +++ b/src/mol-geo/primitive/prism.ts @@ -78,10 +78,22 @@ export function PentagonalPrism() { let hexagonalPrism: Primitive export function HexagonalPrism() { - if (!hexagonalPrism) hexagonalPrism = Prism(polygon(6, true)) + if (!hexagonalPrism) hexagonalPrism = Prism(polygon(6, false)) return hexagonalPrism } +let shiftedHexagonalPrism: Primitive +export function ShiftedHexagonalPrism() { + if (!shiftedHexagonalPrism) shiftedHexagonalPrism = Prism(polygon(6, true)) + return shiftedHexagonalPrism +} + +let heptagonalPrism: Primitive +export function HeptagonalPrism() { + if (!heptagonalPrism) heptagonalPrism = Prism(polygon(7, false)) + return heptagonalPrism +} + // /** @@ -133,6 +145,6 @@ export function PentagonalPrismCage() { let hexagonalPrismCage: Cage export function HexagonalPrismCage() { - if (!hexagonalPrismCage) hexagonalPrismCage = PrismCage(polygon(6, true)) + if (!hexagonalPrismCage) hexagonalPrismCage = PrismCage(polygon(6, false)) return hexagonalPrismCage } \ No newline at end of file diff --git a/src/mol-model/structure/structure/carbohydrates/compute.ts b/src/mol-model/structure/structure/carbohydrates/compute.ts index 183bd430ebdd655d02a432085fc5516aa64852ea..70bd7eb4f0bd5ad1a026c099f61ced0139156c72 100644 --- a/src/mol-model/structure/structure/carbohydrates/compute.ts +++ b/src/mol-model/structure/structure/carbohydrates/compute.ts @@ -1,5 +1,5 @@ /** - * Copyright (c) 2018 mol* contributors, licensed under MIT, See LICENSE file for more info. + * Copyright (c) 2018-2019 mol* contributors, licensed under MIT, See LICENSE file for more info. * * @author Alexander Rose <alexander.rose@weirdbyte.de> * @author David Sehnal <david.sehnal@gmail.com> @@ -203,7 +203,8 @@ export function computeCarbohydrates(structure: Structure): Carbohydrates { elements.push({ geometry: { center, normal, direction }, component: saccharideComp, - unit, residueIndex, anomericCarbon, ringAltId + unit, residueIndex, anomericCarbon, ringAltId, + ringMemberCount: ringAtoms.length }) } diff --git a/src/mol-model/structure/structure/carbohydrates/constants.ts b/src/mol-model/structure/structure/carbohydrates/constants.ts index 7dcb8b51ad3d98cf012da8b64d85098817915ec3..a3ba451b47cb6e2483e2b1d52a5a3164d15bf8b2 100644 --- a/src/mol-model/structure/structure/carbohydrates/constants.ts +++ b/src/mol-model/structure/structure/carbohydrates/constants.ts @@ -1,5 +1,5 @@ /** - * Copyright (c) 2018 mol* contributors, licensed under MIT, See LICENSE file for more info. + * Copyright (c) 2018-2019 mol* contributors, licensed under MIT, See LICENSE file for more info. * * @author Alexander Rose <alexander.rose@weirdbyte.de> * @author David Sehnal <david.sehnal@gmail.com> @@ -9,9 +9,13 @@ import { Color, ColorMap } from '../../../../mol-util/color'; // follows community standard from https://www.ncbi.nlm.nih.gov/glycans/snfg.html -export const enum SaccharideShapes { +export const enum SaccharideShape { + // standard shapes FilledSphere, FilledCube, CrossedCube, DividedDiamond, FilledCone, DevidedCone, - FlatBox, FilledStar, FilledDiamond, FlatDiamond, FlatHexagon, Pentagon + FlatBox, FilledStar, FilledDiamond, FlatDiamond, FlatHexagon, Pentagon, + + // generic shapes for rings with 4, 5, 6, or 7 members + DiamondPrism, PentagonalPrism, HexagonalPrism, HeptagonalPrism } export const SaccharideColors = ColorMap({ @@ -53,22 +57,30 @@ export function getSaccharideName(type: SaccharideType) { } const SaccharideTypeShapeMap = { - [SaccharideType.Hexose]: SaccharideShapes.FilledSphere, - [SaccharideType.HexNAc]: SaccharideShapes.FilledCube, - [SaccharideType.Hexosamine]: SaccharideShapes.CrossedCube, - [SaccharideType.Hexuronate]: SaccharideShapes.DividedDiamond, - [SaccharideType.Deoxyhexose]: SaccharideShapes.FilledCone, - [SaccharideType.DeoxyhexNAc]: SaccharideShapes.DevidedCone, - [SaccharideType.DiDeoxyhexose]: SaccharideShapes.FlatBox, - [SaccharideType.Pentose]: SaccharideShapes.FilledStar, - [SaccharideType.Deoxynonulosonate]: SaccharideShapes.FilledDiamond, - [SaccharideType.DiDeoxynonulosonate]: SaccharideShapes.FlatDiamond, - [SaccharideType.Unknown]: SaccharideShapes.FlatHexagon, - [SaccharideType.Assigned]: SaccharideShapes.Pentagon, + [SaccharideType.Hexose]: SaccharideShape.FilledSphere, + [SaccharideType.HexNAc]: SaccharideShape.FilledCube, + [SaccharideType.Hexosamine]: SaccharideShape.CrossedCube, + [SaccharideType.Hexuronate]: SaccharideShape.DividedDiamond, + [SaccharideType.Deoxyhexose]: SaccharideShape.FilledCone, + [SaccharideType.DeoxyhexNAc]: SaccharideShape.DevidedCone, + [SaccharideType.DiDeoxyhexose]: SaccharideShape.FlatBox, + [SaccharideType.Pentose]: SaccharideShape.FilledStar, + [SaccharideType.Deoxynonulosonate]: SaccharideShape.FilledDiamond, + [SaccharideType.DiDeoxynonulosonate]: SaccharideShape.FlatDiamond, + [SaccharideType.Unknown]: SaccharideShape.FlatHexagon, + [SaccharideType.Assigned]: SaccharideShape.Pentagon, } -export function getSaccharideShape(type: SaccharideType) { - return SaccharideTypeShapeMap[type] +export function getSaccharideShape(type: SaccharideType, ringMemberCount: number): SaccharideShape { + if (type === SaccharideType.Unknown) { + if (ringMemberCount === 4) return SaccharideShape.DiamondPrism + else if (ringMemberCount === 5) return SaccharideShape.PentagonalPrism + else if (ringMemberCount === 6) return SaccharideShape.HexagonalPrism + else if (ringMemberCount === 7) return SaccharideShape.HeptagonalPrism + else return SaccharideShape.FlatHexagon + } else { + return SaccharideTypeShapeMap[type] + } } export type SaccharideComponent = { @@ -172,19 +184,6 @@ const Monosaccharides: SaccharideComponent[] = [ { abbr: 'Tag', name: 'Tagatose', color: SaccharideColors.Yellow, type: SaccharideType.Assigned }, { abbr: 'Sor', name: 'Sorbose', color: SaccharideColors.Orange, type: SaccharideType.Assigned }, { abbr: 'Psi', name: 'Psicose', color: SaccharideColors.Pink, type: SaccharideType.Assigned }, - - { abbr: 'Hexose', name: 'Hexose', color: SaccharideColors.Secondary, type: SaccharideType.Hexose }, - { abbr: 'HexNAc', name: 'HexNAc', color: SaccharideColors.Secondary, type: SaccharideType.HexNAc }, - { abbr: 'Hexosamine', name: 'Hexosamine', color: SaccharideColors.Secondary, type: SaccharideType.Hexosamine }, - { abbr: 'Hexuronate', name: 'Hexuronate', color: SaccharideColors.Secondary, type: SaccharideType.Hexuronate }, - { abbr: 'Deoxyhexose', name: 'Deoxyhexose', color: SaccharideColors.Secondary, type: SaccharideType.Deoxyhexose }, - { abbr: 'DeoxyhexNAc', name: 'DeoxyhexNAc', color: SaccharideColors.Secondary, type: SaccharideType.DeoxyhexNAc }, - { abbr: 'Di-deoxyhexose', name: 'Di-deoxyhexose', color: SaccharideColors.Secondary, type: SaccharideType.DiDeoxyhexose }, - { abbr: 'Pentose', name: 'Pentose', color: SaccharideColors.Secondary, type: SaccharideType.Pentose }, - { abbr: 'Deoxynonulosonate', name: 'Deoxynonulosonate', color: SaccharideColors.Secondary, type: SaccharideType.Deoxynonulosonate }, - { abbr: 'Di-deoxynonulosonate', name: 'Di-deoxynonulosonate', color: SaccharideColors.Secondary, type: SaccharideType.DiDeoxynonulosonate }, - { abbr: 'Unknown', name: 'Unknown', color: SaccharideColors.Secondary, type: SaccharideType.Unknown }, - { abbr: 'Assigned', name: 'Assigned', color: SaccharideColors.Secondary, type: SaccharideType.Assigned }, ] export const SaccharidesSnfgMap = (function () { @@ -301,24 +300,13 @@ const CommonSaccharideNames: { [k: string]: string[] } = { Tag: ['T6T'], Sor: ['SOE'], Psi: ['PSV'], - // Generic - Hexose: [], - HexNAc: [], - Hexosamine: [], - Hexuronate: [], - Deoxyhexose: [], - DeoxyhexNAc: [], - 'Di-deoxyhexose': [], - Pentose: [], - Deoxynonulosonate: [], - 'Di-deoxynonulosonate': [], - Unknown: [], - Assigned: ['PUF'], } const UnknownSaccharideNames = [ 'NGZ', // via CCD 'LAT', // BETA-LACTOSE, Gal-Glc di-saccharide via GlyFinder + + 'PUF', 'GDA', '9WJ', // via updated CCD ] export const SaccharideCompIdMap = (function () { diff --git a/src/mol-model/structure/structure/carbohydrates/data.ts b/src/mol-model/structure/structure/carbohydrates/data.ts index de873ca3c434d12b347602244709c846ce023db7..01aafab225a1396efe624f034c42bf580f9348d3 100644 --- a/src/mol-model/structure/structure/carbohydrates/data.ts +++ b/src/mol-model/structure/structure/carbohydrates/data.ts @@ -1,5 +1,5 @@ /** - * Copyright (c) 2018 mol* contributors, licensed under MIT, See LICENSE file for more info. + * Copyright (c) 2018-2019 mol* contributors, licensed under MIT, See LICENSE file for more info. * * @author Alexander Rose <alexander.rose@weirdbyte.de> */ @@ -30,6 +30,7 @@ export interface CarbohydrateElement { readonly residueIndex: ResidueIndex, readonly component: SaccharideComponent, readonly ringAltId: string, + readonly ringMemberCount: number, } /** partial carbohydrate with no ring present */ diff --git a/src/mol-repr/structure/visual/carbohydrate-symbol-mesh.ts b/src/mol-repr/structure/visual/carbohydrate-symbol-mesh.ts index 93665ab844f151c4cf563ccaaac47ab17d1d4136..14e4299bc671589f449f9188e6124bf5b4a9a2eb 100644 --- a/src/mol-repr/structure/visual/carbohydrate-symbol-mesh.ts +++ b/src/mol-repr/structure/visual/carbohydrate-symbol-mesh.ts @@ -1,5 +1,5 @@ /** - * Copyright (c) 2018 mol* contributors, licensed under MIT, See LICENSE file for more info. + * Copyright (c) 2018-2019 mol* contributors, licensed under MIT, See LICENSE file for more info. * * @author Alexander Rose <alexander.rose@weirdbyte.de> */ @@ -9,11 +9,11 @@ import { Box, PerforatedBox } from '../../../mol-geo/primitive/box'; import { OctagonalPyramid, PerforatedOctagonalPyramid } from '../../../mol-geo/primitive/pyramid'; import { Star } from '../../../mol-geo/primitive/star'; import { Octahedron, PerforatedOctahedron } from '../../../mol-geo/primitive/octahedron'; -import { DiamondPrism, PentagonalPrism, HexagonalPrism } from '../../../mol-geo/primitive/prism'; +import { DiamondPrism, PentagonalPrism, ShiftedHexagonalPrism, HexagonalPrism, HeptagonalPrism } from '../../../mol-geo/primitive/prism'; import { Structure, StructureElement } from '../../../mol-model/structure'; import { Mesh } from '../../../mol-geo/geometry/mesh/mesh'; import { MeshBuilder } from '../../../mol-geo/geometry/mesh/mesh-builder'; -import { getSaccharideShape, SaccharideShapes } from '../../../mol-model/structure/structure/carbohydrates/constants'; +import { getSaccharideShape, SaccharideShape } from '../../../mol-model/structure/structure/carbohydrates/constants'; import { addSphere } from '../../../mol-geo/geometry/mesh/builder/sphere'; import { ComplexMeshParams, ComplexMeshVisual } from '../complex-visual'; import { ParamDefinition as PD } from '../../../mol-util/param-definition'; @@ -43,6 +43,8 @@ const perforatedOctahedron = PerforatedOctahedron() const diamondPrism = DiamondPrism() const pentagonalPrism = PentagonalPrism() const hexagonalPrism = HexagonalPrism() +const shiftedHexagonalPrism = ShiftedHexagonalPrism() +const heptagonalPrism = HeptagonalPrism() function createCarbohydrateSymbolMesh(ctx: VisualContext, structure: Structure, theme: Theme, props: PD.Values<CarbohydrateSymbolParams>, mesh?: Mesh) { const builderState = MeshBuilder.createState(256, 128, mesh) @@ -55,7 +57,7 @@ function createCarbohydrateSymbolMesh(ctx: VisualContext, structure: Structure, for (let i = 0; i < n; ++i) { const c = carbohydrates.elements[i]; - const shapeType = getSaccharideShape(c.component.type) + const shapeType = getSaccharideShape(c.component.type, c.ringMemberCount) l.unit = c.unit l.element = c.unit.elements[c.anomericCarbon] @@ -71,47 +73,47 @@ function createCarbohydrateSymbolMesh(ctx: VisualContext, structure: Structure, builderState.currentGroup = i * 2 switch (shapeType) { - case SaccharideShapes.FilledSphere: + case SaccharideShape.FilledSphere: addSphere(builderState, center, radius, detail) break; - case SaccharideShapes.FilledCube: + case SaccharideShape.FilledCube: Mat4.scaleUniformly(t, t, side) MeshBuilder.addPrimitive(builderState, t, box) break; - case SaccharideShapes.CrossedCube: + case SaccharideShape.CrossedCube: Mat4.scaleUniformly(t, t, side) MeshBuilder.addPrimitive(builderState, t, perforatedBox) Mat4.mul(t, t, Mat4.rotZ90X180) builderState.currentGroup += 1 MeshBuilder.addPrimitive(builderState, t, perforatedBox) break; - case SaccharideShapes.FilledCone: + case SaccharideShape.FilledCone: Mat4.scaleUniformly(t, t, side * 1.2) MeshBuilder.addPrimitive(builderState, t, octagonalPyramid) break - case SaccharideShapes.DevidedCone: + case SaccharideShape.DevidedCone: Mat4.scaleUniformly(t, t, side * 1.2) MeshBuilder.addPrimitive(builderState, t, perforatedOctagonalPyramid) Mat4.mul(t, t, Mat4.rotZ90) builderState.currentGroup += 1 MeshBuilder.addPrimitive(builderState, t, perforatedOctagonalPyramid) break - case SaccharideShapes.FlatBox: + case SaccharideShape.FlatBox: Mat4.mul(t, t, Mat4.rotZY90) Mat4.scale(t, t, Vec3.set(sVec, side, side, side / 2)) MeshBuilder.addPrimitive(builderState, t, box) break - case SaccharideShapes.FilledStar: + case SaccharideShape.FilledStar: Mat4.scaleUniformly(t, t, side) Mat4.mul(t, t, Mat4.rotZY90) MeshBuilder.addPrimitive(builderState, t, star) break - case SaccharideShapes.FilledDiamond: + case SaccharideShape.FilledDiamond: Mat4.mul(t, t, Mat4.rotZY90) Mat4.scale(t, t, Vec3.set(sVec, side * 1.4, side * 1.4, side * 1.4)) MeshBuilder.addPrimitive(builderState, t, octahedron) break - case SaccharideShapes.DividedDiamond: + case SaccharideShape.DividedDiamond: Mat4.mul(t, t, Mat4.rotZY90) Mat4.scale(t, t, Vec3.set(sVec, side * 1.4, side * 1.4, side * 1.4)) MeshBuilder.addPrimitive(builderState, t, perforatedOctahedron) @@ -119,21 +121,37 @@ function createCarbohydrateSymbolMesh(ctx: VisualContext, structure: Structure, builderState.currentGroup += 1 MeshBuilder.addPrimitive(builderState, t, perforatedOctahedron) break - case SaccharideShapes.FlatDiamond: + case SaccharideShape.FlatDiamond: Mat4.mul(t, t, Mat4.rotZY90) Mat4.scale(t, t, Vec3.set(sVec, side, side / 2, side / 2)) MeshBuilder.addPrimitive(builderState, t, diamondPrism) break - case SaccharideShapes.Pentagon: + case SaccharideShape.DiamondPrism: + Mat4.mul(t, t, Mat4.rotZY90) + Mat4.scale(t, t, Vec3.set(sVec, side, side, side / 2)) + MeshBuilder.addPrimitive(builderState, t, diamondPrism) + break + case SaccharideShape.PentagonalPrism: + case SaccharideShape.Pentagon: Mat4.mul(t, t, Mat4.rotZY90) Mat4.scale(t, t, Vec3.set(sVec, side, side, side / 2)) MeshBuilder.addPrimitive(builderState, t, pentagonalPrism) break - case SaccharideShapes.FlatHexagon: + case SaccharideShape.HexagonalPrism: + Mat4.mul(t, t, Mat4.rotZY90) + Mat4.scale(t, t, Vec3.set(sVec, side, side, side / 2)) + MeshBuilder.addPrimitive(builderState, t, hexagonalPrism) + break + case SaccharideShape.HeptagonalPrism: + Mat4.mul(t, t, Mat4.rotZY90) + Mat4.scale(t, t, Vec3.set(sVec, side, side, side / 2)) + MeshBuilder.addPrimitive(builderState, t, heptagonalPrism) + break + case SaccharideShape.FlatHexagon: default: Mat4.mul(t, t, Mat4.rotZYZ90) Mat4.scale(t, t, Vec3.set(sVec, side / 1.5, side , side / 2)) - MeshBuilder.addPrimitive(builderState, t, hexagonalPrism) + MeshBuilder.addPrimitive(builderState, t, shiftedHexagonalPrism) break } }