diff --git a/CHANGELOG.md b/CHANGELOG.md index f4a3a921e923e7e2505b94da6572e34422e07198..7cdd7d49d15fb76b35b401fb5615c33bb0a60d93 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,6 +14,7 @@ Note that since we don't clearly distinguish between a public and private interf - Add Model Export extension - Bugfix: Automatically treat empty string as "non-present" value in BinaryCIF writer. - Fix coarse model support in entity-id color theme +- Fix marking of carbohydrate visuals (whole chain could get marked instead of single residue) ## [v3.0.0-dev.10] - 2022-01-17 diff --git a/src/mol-repr/structure/visual/carbohydrate-link-cylinder.ts b/src/mol-repr/structure/visual/carbohydrate-link-cylinder.ts index be0a198f95543e05488052bc2203eefcff6780f0..b779f658d0ef84682b4db6253818b2a64cd23a22 100644 --- a/src/mol-repr/structure/visual/carbohydrate-link-cylinder.ts +++ b/src/mol-repr/structure/visual/carbohydrate-link-cylinder.ts @@ -1,5 +1,5 @@ /** - * Copyright (c) 2018-2020 mol* contributors, licensed under MIT, See LICENSE file for more info. + * Copyright (c) 2018-2022 mol* contributors, licensed under MIT, See LICENSE file for more info. * * @author Alexander Rose <alexander.rose@weirdbyte.de> */ @@ -101,6 +101,8 @@ function getLinkLoci(pickingId: PickingId, structure: Structure, id: number) { return EmptyLoci; } +const __linkIndicesSet = new Set<number>(); + function eachCarbohydrateLink(loci: Loci, structure: Structure, apply: (interval: Interval) => boolean) { let changed = false; if (!StructureElement.Loci.is(loci)) return false; @@ -110,11 +112,14 @@ function eachCarbohydrateLink(loci: Loci, structure: Structure, apply: (interval for (const { unit, indices } of loci.elements) { if (!Unit.isAtomic(unit)) continue; + __linkIndicesSet.clear(); OrderedSet.forEach(indices, v => { - // TODO avoid duplicate calls to apply const linkIndices = getLinkIndices(unit, unit.elements[v]); for (let i = 0, il = linkIndices.length; i < il; ++i) { - if (apply(Interval.ofSingleton(linkIndices[i]))) changed = true; + if (!__linkIndicesSet.has(linkIndices[i])) { + __linkIndicesSet.add(linkIndices[i]); + if (apply(Interval.ofSingleton(linkIndices[i]))) changed = true; + } } }); } diff --git a/src/mol-repr/structure/visual/carbohydrate-symbol-mesh.ts b/src/mol-repr/structure/visual/carbohydrate-symbol-mesh.ts index 8c56b96b7ef54de11291b0f57982c3ea53e9742b..ab3cfd91a64de3ab5d7cb1ed8f274561797338ce 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-2020 mol* contributors, licensed under MIT, See LICENSE file for more info. + * Copyright (c) 2018-2022 mol* contributors, licensed under MIT, See LICENSE file for more info. * * @author Alexander Rose <alexander.rose@weirdbyte.de> */ @@ -29,8 +29,8 @@ import { getAltResidueLociFromId } from './util/common'; import { BaseGeometry } from '../../../mol-geo/geometry/base'; const t = Mat4.identity(); -const sVec = Vec3.zero(); -const pd = Vec3.zero(); +const sVec = Vec3(); +const pd = Vec3(); const SideFactor = 2 * 0.806; // 0.806 == Math.cos(Math.PI / 4) @@ -212,6 +212,8 @@ function getCarbohydrateLoci(pickingId: PickingId, structure: Structure, id: num return EmptyLoci; } +const __elementIndicesSet = new Set<number>(); + /** For each carbohydrate (usually a monosaccharide) when all its residue's elements are in a loci. */ function eachCarbohydrate(loci: Loci, structure: Structure, apply: (interval: Interval) => boolean) { const { getElementIndices } = structure.carbohydrates; @@ -222,11 +224,14 @@ function eachCarbohydrate(loci: Loci, structure: Structure, apply: (interval: In for (const { unit, indices } of loci.elements) { if (!Unit.isAtomic(unit)) continue; + __elementIndicesSet.clear(); OrderedSet.forEach(indices, v => { - // TODO avoid duplicate calls to apply const elementIndices = getElementIndices(unit, unit.elements[v]); for (let i = 0, il = elementIndices.length; i < il; ++i) { - if (apply(Interval.ofSingleton(elementIndices[i] * 2))) changed = true; + if (!__elementIndicesSet.has(elementIndices[i])) { + __elementIndicesSet.add(elementIndices[i]); + if (apply(Interval.ofSingleton(elementIndices[i] * 2))) changed = true; + } } }); } 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 a95088d747e05eb4f851389752a7d17255c6dcbf..4620b031627009c82b1019f780845bc0d697797f 100644 --- a/src/mol-repr/structure/visual/carbohydrate-terminal-link-cylinder.ts +++ b/src/mol-repr/structure/visual/carbohydrate-terminal-link-cylinder.ts @@ -1,5 +1,5 @@ /** - * Copyright (c) 2018-2020 mol* contributors, licensed under MIT, See LICENSE file for more info. + * Copyright (c) 2018-2022 mol* contributors, licensed under MIT, See LICENSE file for more info. * * @author Alexander Rose <alexander.rose@weirdbyte.de> */ @@ -123,6 +123,8 @@ function getTerminalLinkLoci(pickingId: PickingId, structure: Structure, id: num return EmptyLoci; } +const __linkIndicesSet = new Set<number>(); + function eachTerminalLink(loci: Loci, structure: Structure, apply: (interval: Interval) => boolean) { let changed = false; if (!StructureElement.Loci.is(loci)) return false; @@ -132,11 +134,14 @@ function eachTerminalLink(loci: Loci, structure: Structure, apply: (interval: In for (const { unit, indices } of loci.elements) { if (!Unit.isAtomic(unit)) continue; + __linkIndicesSet.clear(); OrderedSet.forEach(indices, v => { - // TODO avoid duplicate calls to apply const linkIndices = getTerminalLinkIndices(unit, unit.elements[v]); for (let i = 0, il = linkIndices.length; i < il; ++i) { - if (apply(Interval.ofSingleton(linkIndices[i]))) changed = true; + if (!__linkIndicesSet.has(linkIndices[i])) { + __linkIndicesSet.add(linkIndices[i]); + if (apply(Interval.ofSingleton(linkIndices[i]))) changed = true; + } } }); } diff --git a/src/mol-repr/visual.ts b/src/mol-repr/visual.ts index 223b4bfcdb3c794c3af6d58553d48516bc4d084d..90e272b4cb925e35626927f7e9e40b40bc475eb3 100644 --- a/src/mol-repr/visual.ts +++ b/src/mol-repr/visual.ts @@ -1,5 +1,5 @@ /** - * Copyright (c) 2018-2021 mol* contributors, licensed under MIT, See LICENSE file for more info. + * Copyright (c) 2018-2022 mol* contributors, licensed under MIT, See LICENSE file for more info. * * @author Alexander Rose <alexander.rose@weirdbyte.de> */ @@ -88,6 +88,7 @@ namespace Visual { const currentStatus = markerStatus.ref.value as MarkerInfo['status']; if (!isEveryLoci(loci)) { + // assume that all interval are non-overlapping let intervalSize = 0; lociApply(loci, interval => { intervalSize += Interval.size(interval);