diff --git a/src/extensions/dnatco/behavior.ts b/src/extensions/dnatco/behavior.ts index 57ca11ca03eef315f8b9677fbbd995c922c68c02..bbe33f8e9c5c8d700a08926962303d2bc5a7e620 100644 --- a/src/extensions/dnatco/behavior.ts +++ b/src/extensions/dnatco/behavior.ts @@ -39,11 +39,15 @@ export const DnatcoNtCs = PluginBehavior.create<{ autoAttach: boolean, showToolT } unregister() { + this.ctx.customModelProperties.unregister(ConfalPyramidsProvider.descriptor.name); this.ctx.customModelProperties.unregister(NtCTubeProvider.descriptor.name); + this.ctx.representation.structure.registry.remove(ConfalPyramidsRepresentationProvider); + this.ctx.representation.structure.themes.colorThemeRegistry.remove(ConfalPyramidsColorThemeProvider); this.ctx.representation.structure.registry.remove(NtCTubeRepresentationProvider); this.ctx.representation.structure.themes.colorThemeRegistry.remove(NtCTubeColorThemeProvider); + this.ctx.builders.structure.representation.unregisterPreset(ConfalPyramidsPreset); this.ctx.builders.structure.representation.unregisterPreset(NtCTubePreset); } }, diff --git a/src/extensions/dnatco/confal-pyramids/representation.ts b/src/extensions/dnatco/confal-pyramids/representation.ts index f55cb6ef923bbd28f7e7a26c94498b5b95b3e19b..80d9e852af43a66b32f01d1634fbbca0463cc5ec 100644 --- a/src/extensions/dnatco/confal-pyramids/representation.ts +++ b/src/extensions/dnatco/confal-pyramids/representation.ts @@ -88,6 +88,8 @@ function createConfalPyramidsMesh(ctx: VisualContext, unit: Unit, structure: Str const it = new ConfalPyramidsIterator(structure, unit); while (it.hasNext) { const allPoints = it.move(); + if (!allPoints) + continue; for (const points of allPoints) { const { O3, P, OP1, OP2, O5, confalScore } = points; diff --git a/src/extensions/dnatco/confal-pyramids/util.ts b/src/extensions/dnatco/confal-pyramids/util.ts index 6ab28c6f5c9ed549ca7651ec811ed12da11aa28b..c35f3270e893d684bc86e0eb082a64e2c0b9ca69 100644 --- a/src/extensions/dnatco/confal-pyramids/util.ts +++ b/src/extensions/dnatco/confal-pyramids/util.ts @@ -1,5 +1,5 @@ /** - * Copyright (c) 2018-2020 mol* contributors, licensed under MIT, See LICENSE file for more info. + * Copyright (c) 2018-2023 mol* contributors, licensed under MIT, See LICENSE file for more info. * * @author Michal Malý <michal.maly@ibt.cas.cz> * @author Jiřà Černý <jiri.cerny@ibt.cas.cz> @@ -48,6 +48,10 @@ export class ConfalPyramidsIterator { this.residueOne = DnatcoUtil.copyResidue(this.residueTwo); this.residueTwo = DnatcoUtil.copyResidue(this.residueIt.move())!; + // Check for discontinuity + if (this.residueTwo.index !== (this.residueOne!.index + 1)) + return void 0; + return this.toPyramids(this.residueOne!, this.residueTwo); } diff --git a/src/extensions/dnatco/ntc-tube/util.ts b/src/extensions/dnatco/ntc-tube/util.ts index 84d4f341b2468892e8ea009b2a4a7b18212c8dbe..36f436358cd5eaa059010413efa2dc22a3ed72ca 100644 --- a/src/extensions/dnatco/ntc-tube/util.ts +++ b/src/extensions/dnatco/ntc-tube/util.ts @@ -74,23 +74,59 @@ export type NtCTubeSegment = { export class NtCTubeSegmentsIterator { private chainIt: Segmentation.SegmentIterator<ChainIndex>; private residueIt: Segmentation.SegmentIterator<ResidueIndex>; + + /* Second residue of the previous step, may be undefined + * if we are at the beginning of a chain or right after a discontinuity */ private residuePrev?: DnatcoUtil.Residue; + /* First residue of the current step */ private residueOne?: DnatcoUtil.Residue; + /* Second residue of the current step */ private residueTwo: DnatcoUtil.Residue; + /* First residue of the next step, may be undefined + * if we are at the end of a chain. + * Undefined value indicates that the iterator has reached the end.*/ + private residueNext?: DnatcoUtil.Residue; + private data?: NTT.Data; private altIdOne = ''; private insCodeOne = ''; private loc: StructureElement.Location; private moveStep() { - this.residuePrev = DnatcoUtil.copyResidue(this.residueOne); - this.residueOne = DnatcoUtil.copyResidue(this.residueTwo); - this.residueTwo = DnatcoUtil.copyResidue(this.residueIt.move())!; + if (!this.residueNext) + return void 0; + + /* Assume discontinuity of the ResidueIndex of the residue that would become residue one (= first residue of the corresponding step) + * does not equal to ResidueIndex of what would be residue two (= second residue of the corresponding step). */ + if (this.residueTwo.index + 1 === this.residueNext.index) { + this.residuePrev = DnatcoUtil.copyResidue(this.residueOne); + this.residueOne = DnatcoUtil.copyResidue(this.residueTwo); + this.residueTwo = DnatcoUtil.copyResidue(this.residueNext)!; + this.residueNext = this.residueIt.hasNext ? DnatcoUtil.copyResidue(this.residueIt.move())! : void 0; + } else { + if (!this.residueIt.hasNext) { + this.residueNext = void 0; + return void 0; + } + + // There is discontinuity, act as if we were at the beginning of a chain + this.residuePrev = void 0; + this.residueOne = DnatcoUtil.copyResidue(this.residueNext); + this.residueTwo = DnatcoUtil.copyResidue(this.residueIt.move())!; + this.residueNext = this.residueIt.hasNext ? DnatcoUtil.copyResidue(this.residueIt.move())! : void 0; + } + + return this.toSegment(this.residuePrev, this.residueOne!, this.residueTwo, this.residueNext); + } - return this.toSegment(this.residuePrev, this.residueOne!, this.residueTwo); + private prime() { + if (this.residueIt.hasNext) + this.residueTwo = DnatcoUtil.copyResidue(this.residueIt.move())!; + if (this.residueIt.hasNext) + this.residueNext = this.residueIt.move(); } - private toSegment(r0: DnatcoUtil.Residue | undefined, r1: DnatcoUtil.Residue, r2: DnatcoUtil.Residue): NtCTubeSegment | undefined { + private toSegment(r0: DnatcoUtil.Residue | undefined, r1: DnatcoUtil.Residue, r2: DnatcoUtil.Residue, r3: DnatcoUtil.Residue | undefined): NtCTubeSegment | undefined { const indices = DnatcoUtil.getStepIndices(this.data!.data, this.loc, r1); if (indices.length === 0) return void 0; @@ -105,13 +141,14 @@ export class NtCTubeSegmentsIterator { const altIdTwo = step.label_alt_id_2; const insCodeTwo = step.PDB_ins_code_2; const followsGap = !!r0 && hasGapElements(r0, this.loc.unit) && hasGapElements(r1, this.loc.unit); + const precedesDiscontinuity = r3 ? r3.index !== r2.index + 1 : false; return { ...getPoints(this.loc, r0, r1, r2, altIdPrev, this.altIdOne, altIdTwo, insCodePrev, this.insCodeOne, insCodeTwo), stepIdx, followsGap, firstInChain: !r0, - capEnd: !this.residueIt.hasNext || hasGapElements(r2, this.loc.unit), + capEnd: !this.residueNext || precedesDiscontinuity || hasGapElements(r2, this.loc.unit), }; } @@ -124,8 +161,7 @@ export class NtCTubeSegmentsIterator { if (this.chainIt.hasNext) { this.residueIt.setSegment(this.chainIt.move()); - if (this.residueIt.hasNext) - this.residueTwo = this.residueIt.move(); + this.prime(); } this.loc = StructureElement.Location.create(structure, unit, -1 as ElementIndex); @@ -134,19 +170,21 @@ export class NtCTubeSegmentsIterator { get hasNext() { if (!this.data) return false; - return this.residueIt.hasNext + return !!this.residueNext ? true : this.chainIt.hasNext; } move() { - if (this.residueIt.hasNext) { + if (!!this.residueNext) { return this.moveStep(); } else { this.residuePrev = void 0; // Assume discontinuity when we switch chains + this.residueNext = void 0; + this.residueIt.setSegment(this.chainIt.move()); - if (this.residueIt.hasNext) - this.residueTwo = this.residueIt.move(); + this.prime(); + return this.moveStep(); } }