diff --git a/CHANGELOG.md b/CHANGELOG.md index 8f4fe35f873a06fed51681d0bf9b0712dfb7b22b..f3016fe910dd92cc61dbe3938d9d727f72d85860 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,9 @@ Note that since we don't clearly distinguish between a public and private interf ## [Unreleased] +- Improve aromatic bond visuals (add ``aromaticScale``, ``aromaticSpacing``, ``aromaticDashCount`` params) +- [Breaking] Change ``adjustCylinderLength`` default to ``false`` (set to true for focus representation) + ## [v2.3.5] - 2021-10-19 - Fix sequence viewer for PDB files with COMPND record and multichain entities. @@ -153,29 +156,22 @@ Note that since we don't clearly distinguish between a public and private interf - Fixed Measurements UI labels (#166) ## [v2.0.3] - 2021-04-09 -### Added -- Support for ``ColorTheme.palette`` designed for providing gradient-like coloring. -### Changed +- Add support for ``ColorTheme.palette`` designed for providing gradient-like coloring. - [Breaking] The ``zip`` function is now asynchronous and expects a ``RuntimeContext``. Also added ``Zip()`` returning a ``Task``. - [Breaking] Add ``CubeGridFormat`` in ``alpha-orbitals`` extension. ## [v2.0.2] - 2021-03-29 -### Added -- ``Canvas3D.getRenderObjects``. -- [WIP] Animate state interpolating, including model trajectories -### Changed +- Add ``Canvas3D.getRenderObjects``. +- [WIP] Animate state interpolating, including model trajectories - Recognise MSE, SEP, TPO, PTR and PCA as non-standard amino-acids. - -### Fixed -- VolumeFromDensityServerCif transform label - +- Fix VolumeFromDensityServerCif transform label ## [v2.0.1] - 2021-03-23 -### Fixed -- Exclude tsconfig.commonjs.tsbuildinfo from npm bundle +- Exclude tsconfig.commonjs.tsbuildinfo from npm bundle ## [v2.0.0] - 2021-03-23 + Too many changes to list as this is the start of the changelog... Notably, default exports are now forbidden. diff --git a/src/mol-plugin/behavior/dynamic/selection/structure-focus-representation.ts b/src/mol-plugin/behavior/dynamic/selection/structure-focus-representation.ts index 43ad81abd070d9b3d51ec70d004b6bc6ce6ff664..fbd8fa87c570f069641eacf95c3e36b46badd536 100644 --- a/src/mol-plugin/behavior/dynamic/selection/structure-focus-representation.ts +++ b/src/mol-plugin/behavior/dynamic/selection/structure-focus-representation.ts @@ -25,7 +25,7 @@ const StructureFocusRepresentationParams = (plugin: PluginContext) => { expandRadius: PD.Numeric(5, { min: 1, max: 10, step: 1 }), targetParams: PD.Group(reprParams, { label: 'Target', - customDefault: createStructureRepresentationParams(plugin, void 0, { type: 'ball-and-stick', size: 'physical', typeParams: { sizeFactor: 0.26, alpha: 0.51 } }) + customDefault: createStructureRepresentationParams(plugin, void 0, { type: 'ball-and-stick', size: 'physical', typeParams: { sizeFactor: 0.26, alpha: 0.51, adjustCylinderLength: true } }) }), surroundingsParams: PD.Group(reprParams, { label: 'Surroundings', diff --git a/src/mol-repr/structure/visual/bond-inter-unit-cylinder.ts b/src/mol-repr/structure/visual/bond-inter-unit-cylinder.ts index c735dbeaeac4b67371671abddc47e9aa9a1398a5..5385bac813dbc3f0b461d149c8d9d3a116de447f 100644 --- a/src/mol-repr/structure/visual/bond-inter-unit-cylinder.ts +++ b/src/mol-repr/structure/visual/bond-inter-unit-cylinder.ts @@ -215,6 +215,9 @@ export function InterUnitBondCylinderImpostorVisual(materialId: number): Complex newProps.linkSpacing !== currentProps.linkSpacing || newProps.ignoreHydrogens !== currentProps.ignoreHydrogens || newProps.linkCap !== currentProps.linkCap || + newProps.aromaticScale !== currentProps.aromaticScale || + newProps.aromaticSpacing !== currentProps.aromaticSpacing || + newProps.aromaticDashCount !== currentProps.aromaticDashCount || newProps.dashCount !== currentProps.dashCount || newProps.dashScale !== currentProps.dashScale || newProps.dashCap !== currentProps.dashCap || @@ -254,6 +257,9 @@ export function InterUnitBondCylinderMeshVisual(materialId: number): ComplexVisu newProps.linkSpacing !== currentProps.linkSpacing || newProps.ignoreHydrogens !== currentProps.ignoreHydrogens || newProps.linkCap !== currentProps.linkCap || + newProps.aromaticScale !== currentProps.aromaticScale || + newProps.aromaticSpacing !== currentProps.aromaticSpacing || + newProps.aromaticDashCount !== currentProps.aromaticDashCount || newProps.dashCount !== currentProps.dashCount || newProps.dashScale !== currentProps.dashScale || newProps.dashCap !== currentProps.dashCap || diff --git a/src/mol-repr/structure/visual/bond-inter-unit-line.ts b/src/mol-repr/structure/visual/bond-inter-unit-line.ts index 62c030b93f5533c4ee499c60c4a126ef66329e12..1fb4b9784d8fe7cfbb7a56fa27a9243d96ab69f0 100644 --- a/src/mol-repr/structure/visual/bond-inter-unit-line.ts +++ b/src/mol-repr/structure/visual/bond-inter-unit-line.ts @@ -131,6 +131,7 @@ export function InterUnitBondLineVisual(materialId: number): ComplexVisual<Inter newProps.sizeFactor !== currentProps.sizeFactor || newProps.linkScale !== currentProps.linkScale || newProps.linkSpacing !== currentProps.linkSpacing || + newProps.aromaticDashCount !== currentProps.aromaticDashCount || newProps.dashCount !== currentProps.dashCount || newProps.ignoreHydrogens !== currentProps.ignoreHydrogens || !arrayEqual(newProps.includeTypes, currentProps.includeTypes) || diff --git a/src/mol-repr/structure/visual/bond-intra-unit-cylinder.ts b/src/mol-repr/structure/visual/bond-intra-unit-cylinder.ts index 3e42f0cc066fa5b14bad7a9f83b35b5e1363d01b..abd5d82a7282c0f403faec6fbb92597030c134f5 100644 --- a/src/mol-repr/structure/visual/bond-intra-unit-cylinder.ts +++ b/src/mol-repr/structure/visual/bond-intra-unit-cylinder.ts @@ -228,6 +228,9 @@ export function IntraUnitBondCylinderImpostorVisual(materialId: number): UnitsVi newProps.linkSpacing !== currentProps.linkSpacing || newProps.ignoreHydrogens !== currentProps.ignoreHydrogens || newProps.linkCap !== currentProps.linkCap || + newProps.aromaticScale !== currentProps.aromaticScale || + newProps.aromaticSpacing !== currentProps.aromaticSpacing || + newProps.aromaticDashCount !== currentProps.aromaticDashCount || newProps.dashCount !== currentProps.dashCount || newProps.dashScale !== currentProps.dashScale || newProps.dashCap !== currentProps.dashCap || @@ -272,6 +275,9 @@ export function IntraUnitBondCylinderMeshVisual(materialId: number): UnitsVisual newProps.linkSpacing !== currentProps.linkSpacing || newProps.ignoreHydrogens !== currentProps.ignoreHydrogens || newProps.linkCap !== currentProps.linkCap || + newProps.aromaticScale !== currentProps.aromaticScale || + newProps.aromaticSpacing !== currentProps.aromaticSpacing || + newProps.aromaticDashCount !== currentProps.aromaticDashCount || newProps.dashCount !== currentProps.dashCount || newProps.dashScale !== currentProps.dashScale || newProps.dashCap !== currentProps.dashCap || diff --git a/src/mol-repr/structure/visual/bond-intra-unit-line.ts b/src/mol-repr/structure/visual/bond-intra-unit-line.ts index 10708af2f9f5b6e92df1ccf9afc6a761e66efd6d..1ad1fa45f7bbbad9eda44e63e311bd0e995925a4 100644 --- a/src/mol-repr/structure/visual/bond-intra-unit-line.ts +++ b/src/mol-repr/structure/visual/bond-intra-unit-line.ts @@ -153,6 +153,7 @@ export function IntraUnitBondLineVisual(materialId: number): UnitsVisual<IntraUn newProps.sizeFactor !== currentProps.sizeFactor || newProps.linkScale !== currentProps.linkScale || newProps.linkSpacing !== currentProps.linkSpacing || + newProps.aromaticDashCount !== currentProps.aromaticDashCount || newProps.dashCount !== currentProps.dashCount || newProps.ignoreHydrogens !== currentProps.ignoreHydrogens || !arrayEqual(newProps.includeTypes, currentProps.includeTypes) || diff --git a/src/mol-repr/structure/visual/util/bond.ts b/src/mol-repr/structure/visual/util/bond.ts index 11fd2cf27adf49274b85e6fab523a4e7ce936d33..d2fb94a7769d27880135d6008e0c46c724ae1ef4 100644 --- a/src/mol-repr/structure/visual/util/bond.ts +++ b/src/mol-repr/structure/visual/util/bond.ts @@ -28,7 +28,7 @@ export type BondProps = typeof DefaultBondProps export const BondCylinderParams = { ...LinkCylinderParams, ...BondParams, - adjustCylinderLength: PD.Boolean(true, { description: 'Shorten cylinders to reduce overlap with spheres.' }) + adjustCylinderLength: PD.Boolean(false, { description: 'Shorten cylinders to reduce overlap with spheres. Useful for for transparent bonds. Not working well with aromatic bonds.' }) }; export const DefaultBondCylinderProps = PD.getDefaultValues(BondCylinderParams); export type BondCylinderProps = typeof DefaultBondCylinderProps diff --git a/src/mol-repr/structure/visual/util/link.ts b/src/mol-repr/structure/visual/util/link.ts index f28aef6918560ea4c199a515931d3222292252b6..c62aea5d0a496badcf2924404c35ce6153cf9c3f 100644 --- a/src/mol-repr/structure/visual/util/link.ts +++ b/src/mol-repr/structure/visual/util/link.ts @@ -21,6 +21,9 @@ export const LinkCylinderParams = { linkScale: PD.Numeric(0.45, { min: 0, max: 1, step: 0.01 }), linkSpacing: PD.Numeric(1, { min: 0, max: 2, step: 0.01 }), linkCap: PD.Boolean(false), + aromaticScale: PD.Numeric(0.3, { min: 0, max: 1, step: 0.01 }), + aromaticSpacing: PD.Numeric(1.5, { min: 0, max: 3, step: 0.01 }), + aromaticDashCount: PD.Numeric(2, { min: 2, max: 6, step: 2 }), dashCount: PD.Numeric(4, { min: 2, max: 10, step: 2 }), dashScale: PD.Numeric(0.8, { min: 0, max: 2, step: 0.1 }), dashCap: PD.Boolean(true), @@ -33,6 +36,7 @@ export type LinkCylinderProps = typeof DefaultLinkCylinderProps export const LinkLineParams = { linkScale: PD.Numeric(0.5, { min: 0, max: 1, step: 0.1 }), linkSpacing: PD.Numeric(0.1, { min: 0, max: 2, step: 0.01 }), + aromaticDashCount: PD.Numeric(2, { min: 2, max: 6, step: 2 }), dashCount: PD.Numeric(4, { min: 2, max: 10, step: 2 }), }; export const DefaultLinkLineProps = PD.getDefaultValues(LinkLineParams); @@ -107,7 +111,7 @@ export function createLinkCylinderMesh(ctx: VisualContext, linkBuilder: LinkBuil if (!linkCount) return Mesh.createEmpty(mesh); - const { linkScale, linkSpacing, radialSegments, linkCap, dashCount, dashScale, dashCap, stubCap } = props; + const { linkScale, linkSpacing, radialSegments, linkCap, aromaticScale, aromaticSpacing, aromaticDashCount, dashCount, dashScale, dashCap, stubCap } = props; const vertexCountEstimate = radialSegments * 2 * linkCount * 2; const builderState = MeshBuilder.createState(vertexCountEstimate, vertexCountEstimate / 4, mesh); @@ -138,8 +142,7 @@ export function createLinkCylinderMesh(ctx: VisualContext, linkBuilder: LinkBuil const [topCap, bottomCap] = dirFlag ? [linkStub, linkCap] : [linkCap, linkStub]; builderState.currentGroup = edgeIndex; - const aromaticOffsetFactor = 5.5; - const multipleOffsetFactor = 4; + const aromaticSegmentCount = aromaticDashCount + 1; if (linkStyle === LinkStyle.Solid) { cylinderProps.radiusTop = cylinderProps.radiusBottom = linkRadius; @@ -153,8 +156,8 @@ export function createLinkCylinderMesh(ctx: VisualContext, linkBuilder: LinkBuil addFixedCountDashedCylinder(builderState, va, vb, 0.5, segmentCount, cylinderProps); } else if (linkStyle === LinkStyle.Double || linkStyle === LinkStyle.OffsetDouble || linkStyle === LinkStyle.Triple || linkStyle === LinkStyle.OffsetTriple || linkStyle === LinkStyle.Aromatic || linkStyle === LinkStyle.MirroredAromatic) { - const order = linkStyle === LinkStyle.Double || linkStyle === LinkStyle.OffsetDouble ? 2 : - linkStyle === LinkStyle.Triple || linkStyle === LinkStyle.OffsetTriple ? 3 : 1.5; + const order = (linkStyle === LinkStyle.Double || linkStyle === LinkStyle.OffsetDouble) ? 2 : + (linkStyle === LinkStyle.Triple || linkStyle === LinkStyle.OffsetTriple) ? 3 : 1.5; const multiRadius = linkRadius * (linkScale / (0.5 * order)); const absOffset = (linkRadius - multiRadius) * linkSpacing; @@ -167,21 +170,28 @@ export function createLinkCylinderMesh(ctx: VisualContext, linkBuilder: LinkBuil cylinderProps.radiusTop = cylinderProps.radiusBottom = linkRadius; addCylinder(builderState, va, vb, 0.5, cylinderProps); - cylinderProps.radiusTop = cylinderProps.radiusBottom = linkRadius * linkScale; + const aromaticOffset = linkRadius + aromaticScale * linkRadius + aromaticScale * linkRadius * aromaticSpacing; + + v3setMagnitude(tmpV12, v3sub(tmpV12, vb, va), linkRadius * 0.5); + v3add(va, va, tmpV12); + v3sub(vb, vb, tmpV12); + + cylinderProps.radiusTop = cylinderProps.radiusBottom = linkRadius * aromaticScale; cylinderProps.topCap = cylinderProps.bottomCap = dashCap; - v3setMagnitude(vShift, vShift, absOffset * aromaticOffsetFactor); + v3setMagnitude(vShift, vShift, aromaticOffset); v3sub(va, va, vShift); v3sub(vb, vb, vShift); - addFixedCountDashedCylinder(builderState, va, vb, 0.5, 3, cylinderProps); + addFixedCountDashedCylinder(builderState, va, vb, 0.5, aromaticSegmentCount, cylinderProps); if (linkStyle === LinkStyle.MirroredAromatic) { - v3setMagnitude(vShift, vShift, absOffset * aromaticOffsetFactor * 2); + v3setMagnitude(vShift, vShift, aromaticOffset * 2); v3add(va, va, vShift); v3add(vb, vb, vShift); - addFixedCountDashedCylinder(builderState, va, vb, 0.5, 3, cylinderProps); + addFixedCountDashedCylinder(builderState, va, vb, 0.5, aromaticSegmentCount, cylinderProps); } } else if (linkStyle === LinkStyle.OffsetDouble || linkStyle === LinkStyle.OffsetTriple) { - v3setMagnitude(vShift, vShift, absOffset); + const multipleOffset = linkRadius + multiRadius + linkScale * linkRadius * linkSpacing; + v3setMagnitude(vShift, vShift, multipleOffset); cylinderProps.radiusTop = cylinderProps.radiusBottom = linkRadius; addCylinder(builderState, va, vb, 0.5, cylinderProps); @@ -193,13 +203,13 @@ export function createLinkCylinderMesh(ctx: VisualContext, linkBuilder: LinkBuil cylinderProps.radiusTop = cylinderProps.radiusBottom = multiRadius; cylinderProps.topCap = dirFlag ? linkStub : dashCap; cylinderProps.bottomCap = dirFlag ? dashCap : linkStub; - v3setMagnitude(vShift, vShift, absOffset * multipleOffsetFactor); + v3setMagnitude(vShift, vShift, multipleOffset); v3sub(va, va, vShift); v3sub(vb, vb, vShift); addCylinder(builderState, va, vb, 0.5, cylinderProps); if (order === 3) { - v3setMagnitude(vShift, vShift, absOffset * multipleOffsetFactor * 2); + v3setMagnitude(vShift, vShift, multipleOffset * 2); v3add(va, va, vShift); v3add(vb, vb, vShift); addCylinder(builderState, va, vb, 0.5, cylinderProps); @@ -236,7 +246,7 @@ export function createLinkCylinderImpostors(ctx: VisualContext, linkBuilder: Lin if (!linkCount) return Cylinders.createEmpty(cylinders); - const { linkScale, linkSpacing, linkCap, dashCount, dashScale, dashCap, stubCap } = props; + const { linkScale, linkSpacing, linkCap, aromaticScale, aromaticSpacing, aromaticDashCount, dashCount, dashScale, dashCap, stubCap } = props; const cylindersCountEstimate = linkCount * 2; const builder = CylindersBuilder.create(cylindersCountEstimate, cylindersCountEstimate / 4, cylinders); @@ -250,10 +260,8 @@ export function createLinkCylinderImpostors(ctx: VisualContext, linkBuilder: Lin const segmentCount = dashCount % 2 === 1 ? dashCount : dashCount + 1; const lengthScale = 0.5 - (0.5 / 2 / segmentCount); - const aromaticSegmentCount = 3; + const aromaticSegmentCount = aromaticDashCount + 1; const aromaticLengthScale = 0.5 - (0.5 / 2 / aromaticSegmentCount); - const aromaticOffsetFactor = 5.5; - const multipleOffsetFactor = 4; for (let edgeIndex = 0, _eI = linkCount; edgeIndex < _eI; ++edgeIndex) { if (ignore && ignore(edgeIndex)) continue; @@ -272,8 +280,8 @@ export function createLinkCylinderImpostors(ctx: VisualContext, linkBuilder: Lin v3sub(vb, vb, tmpV12); builder.addFixedCountDashes(va, vb, segmentCount, dashScale, dashCap, dashCap, edgeIndex); } else if (linkStyle === LinkStyle.Double || linkStyle === LinkStyle.OffsetDouble || linkStyle === LinkStyle.Triple || linkStyle === LinkStyle.OffsetTriple || linkStyle === LinkStyle.Aromatic || linkStyle === LinkStyle.MirroredAromatic) { - const order = linkStyle === LinkStyle.Double || linkStyle === LinkStyle.OffsetDouble ? 2 : - linkStyle === LinkStyle.Triple || linkStyle === LinkStyle.OffsetTriple ? 3 : 1.5; + const order = (linkStyle === LinkStyle.Double || linkStyle === LinkStyle.OffsetDouble) ? 2 : + (linkStyle === LinkStyle.Triple || linkStyle === LinkStyle.OffsetTriple) ? 3 : 1.5; const multiScale = linkScale / (0.5 * order); const absOffset = (linkRadius - multiScale * linkRadius) * linkSpacing; @@ -283,26 +291,32 @@ export function createLinkCylinderImpostors(ctx: VisualContext, linkBuilder: Lin if (linkStyle === LinkStyle.Aromatic || linkStyle === LinkStyle.MirroredAromatic) { builder.add(va[0], va[1], va[2], vm[0], vm[1], vm[2], 1, linkCap, linkStub, edgeIndex); + const aromaticOffset = linkRadius + aromaticScale * linkRadius + aromaticScale * linkRadius * aromaticSpacing; + v3scale(tmpV12, v3sub(tmpV12, vb, va), aromaticLengthScale); v3sub(vb, vb, tmpV12); - v3setMagnitude(vShift, vShift, absOffset * aromaticOffsetFactor); + v3setMagnitude(tmpV12, v3sub(tmpV12, vb, va), linkRadius * 0.5); + v3add(va, va, tmpV12); + + v3setMagnitude(vShift, vShift, aromaticOffset); v3sub(va, va, vShift); v3sub(vb, vb, vShift); - builder.addFixedCountDashes(va, vb, aromaticSegmentCount, linkScale, dashCap, dashCap, edgeIndex); + builder.addFixedCountDashes(va, vb, aromaticSegmentCount, aromaticScale, dashCap, dashCap, edgeIndex); if (linkStyle === LinkStyle.MirroredAromatic) { - v3setMagnitude(vShift, vShift, absOffset * aromaticOffsetFactor * 2); + v3setMagnitude(vShift, vShift, aromaticOffset * 2); v3add(va, va, vShift); v3add(vb, vb, vShift); - builder.addFixedCountDashes(va, vb, aromaticSegmentCount, linkScale, dashCap, dashCap, edgeIndex); + builder.addFixedCountDashes(va, vb, aromaticSegmentCount, aromaticScale, dashCap, dashCap, edgeIndex); } } else if (linkStyle === LinkStyle.OffsetDouble || linkStyle === LinkStyle.OffsetTriple) { - v3setMagnitude(vShift, vShift, absOffset * multipleOffsetFactor); + const multipleOffset = linkRadius + multiScale * linkRadius + linkScale * linkRadius * linkSpacing; + v3setMagnitude(vShift, vShift, multipleOffset); builder.add(va[0], va[1], va[2], vm[0], vm[1], vm[2], 1, linkCap, linkStub, edgeIndex); - v3scale(tmpV12, v3sub(tmpV12, va, vb), linkSpacing * linkScale * 0.2); + v3setMagnitude(tmpV12, v3sub(tmpV12, va, vb), linkRadius / 1.5); v3sub(va, va, tmpV12); if (order === 3) builder.add(va[0] + vShift[0], va[1] + vShift[1], va[2] + vShift[2], vm[0] + vShift[0], vm[1] + vShift[1], vm[2] + vShift[2], multiScale, linkCap, linkStub, edgeIndex); @@ -335,7 +349,7 @@ export function createLinkLines(ctx: VisualContext, linkBuilder: LinkBuilderProp if (!linkCount) return Lines.createEmpty(lines); - const { linkScale, linkSpacing, dashCount } = props; + const { linkScale, linkSpacing, aromaticDashCount, dashCount } = props; const linesCountEstimate = linkCount * 2; const builder = LinesBuilder.create(linesCountEstimate, linesCountEstimate / 4, lines); @@ -349,7 +363,7 @@ export function createLinkLines(ctx: VisualContext, linkBuilder: LinkBuilderProp const segmentCount = dashCount % 2 === 1 ? dashCount : dashCount + 1; const lengthScale = 0.5 - (0.5 / 2 / segmentCount); - const aromaticSegmentCount = 3; + const aromaticSegmentCount = aromaticDashCount + 1; const aromaticLengthScale = 0.5 - (0.5 / 2 / aromaticSegmentCount); const aromaticOffsetFactor = 4.5; const multipleOffsetFactor = 3;