Skip to content
Snippets Groups Projects
Select Git revision
  • b1755604e29e7f28f8960f3ce62cceed5de5aa67
  • master default protected
  • rednatco-v2
  • rednatco
  • test
  • ntc-tube-uniform-color
  • ntc-tube-missing-atoms
  • restore-vertex-array-per-program
  • watlas2
  • dnatco_new
  • cleanup-old-nodejs
  • webmmb
  • fix_auth_seq_id
  • update_deps
  • ext_dev
  • ntc_balls
  • nci-2
  • plugin
  • bugfix-0.4.5
  • nci
  • servers
  • v0.5.0-dev.1
  • v0.4.5
  • v0.4.4
  • v0.4.3
  • v0.4.2
  • v0.4.1
  • v0.4.0
  • v0.3.12
  • v0.3.11
  • v0.3.10
  • v0.3.9
  • v0.3.8
  • v0.3.7
  • v0.3.6
  • v0.3.5
  • v0.3.4
  • v0.3.3
  • v0.3.2
  • v0.3.1
  • v0.3.0
41 results

renderable.ts

Blame
  • trace-iterator.ts 12.44 KiB
    /**
     * Copyright (c) 2018 mol* contributors, licensed under MIT, See LICENSE file for more info.
     *
     * @author Alexander Rose <alexander.rose@weirdbyte.de>
     */
    
    import { Unit, StructureElement, ElementIndex, ResidueIndex } from 'mol-model/structure';
    import { Segmentation } from 'mol-data/int';
    import { MoleculeType, SecondaryStructureType, AtomRole } from 'mol-model/structure/model/types';
    import Iterator from 'mol-data/iterator';
    import { Vec3 } from 'mol-math/linear-algebra';
    import SortedRanges from 'mol-data/int/sorted-ranges';
    import { CoarseSphereConformation, CoarseGaussianConformation } from 'mol-model/structure/model/properties/coarse';
    import { getAtomicMoleculeType, getElementIndexForAtomRole } from 'mol-model/structure/util';
    import { getPolymerRanges } from '../polymer';
    import { AtomicConformation } from 'mol-model/structure/model/properties/atomic';
    
    /**
     * Iterates over individual residues/coarse elements in polymers of a unit while
     * providing information about the neighbourhood in the underlying model for drawing splines
     */
    export function PolymerTraceIterator(unit: Unit): Iterator<PolymerTraceElement> {
        switch (unit.kind) {
            case Unit.Kind.Atomic: return new AtomicPolymerTraceIterator(unit)
            case Unit.Kind.Spheres:
            case Unit.Kind.Gaussians:
                return new CoarsePolymerTraceIterator(unit)
        }
    }
    
    interface PolymerTraceElement {
        center: StructureElement
        first: boolean, last: boolean
        secStrucFirst: boolean, secStrucLast: boolean
        secStrucType: SecondaryStructureType
        moleculeType: MoleculeType
    
        p0: Vec3, p1: Vec3, p2: Vec3, p3: Vec3, p4: Vec3
        d12: Vec3, d23: Vec3
    }
    
    const SecStrucTypeNA = SecondaryStructureType.create(SecondaryStructureType.Flag.NA)
    
    function createPolymerTraceElement (unit: Unit): PolymerTraceElement {
        return {
            center: StructureElement.create(unit),
            first: false, last: false,
            secStrucFirst: false, secStrucLast: false,
            secStrucType: SecStrucTypeNA,
            moleculeType: MoleculeType.unknown,
            p0: Vec3.zero(), p1: Vec3.zero(), p2: Vec3.zero(), p3: Vec3.zero(), p4: Vec3.zero(),
            d12: Vec3.create(1, 0, 0), d23: Vec3.create(1, 0, 0),
        }
    }
    
    const enum AtomicPolymerTraceIteratorState { nextPolymer, nextResidue }
    
    export class AtomicPolymerTraceIterator implements Iterator<PolymerTraceElement> {
        private value: PolymerTraceElement
        private polymerIt: SortedRanges.Iterator<ElementIndex, ResidueIndex>
        private residueIt: Segmentation.SegmentIterator<ResidueIndex>
        private polymerSegment: Segmentation.Segment<ResidueIndex>
        private cyclicPolymerMap: Map<ResidueIndex, ResidueIndex>
        private secondaryStructureType: ArrayLike<SecondaryStructureType>
        private residueSegmentMin: ResidueIndex
        private residueSegmentMax: ResidueIndex
        private prevSecStrucType: SecondaryStructureType
        private currSecStrucType: SecondaryStructureType
        private nextSecStrucType: SecondaryStructureType
        private state: AtomicPolymerTraceIteratorState = AtomicPolymerTraceIteratorState.nextPolymer
        private residueAtomSegments: Segmentation<ElementIndex, ResidueIndex>
        private atomicConformation: AtomicConformation
    
        private p0 = Vec3.zero();
        private p1 = Vec3.zero();
        private p2 = Vec3.zero();
        private p3 = Vec3.zero();
        private p4 = Vec3.zero();
        private p5 = Vec3.zero();
        private p6 = Vec3.zero();
    
        // private v01 = Vec3.zero();
        private v12 = Vec3.zero();
        private v23 = Vec3.zero();
        // private v34 = Vec3.zero();
    
        hasNext: boolean = false;
    
        private pos(target: Vec3, index: number) {
            target[0] = this.atomicConformation.x[index]
            target[1] = this.atomicConformation.y[index]
            target[2] = this.atomicConformation.z[index]
        }
    
        private updateResidueSegmentRange(polymerSegment: Segmentation.Segment<ResidueIndex>) {
            const { index } = this.residueAtomSegments
            this.residueSegmentMin = index[this.unit.elements[polymerSegment.start]]
            this.residueSegmentMax = index[this.unit.elements[polymerSegment.end - 1]]
        }
    
        private getElementIndex(residueIndex: ResidueIndex, atomRole: AtomRole) {
            if (residueIndex < this.residueSegmentMin) {
                const cyclicIndex = this.cyclicPolymerMap.get(this.residueSegmentMin)
                if (cyclicIndex !== undefined) {
                    residueIndex = cyclicIndex - (this.residueSegmentMin - residueIndex - 1) as ResidueIndex
                } else {
                    residueIndex = this.residueSegmentMin
                }
            } else if (residueIndex > this.residueSegmentMax) {
                const cyclicIndex = this.cyclicPolymerMap.get(this.residueSegmentMax)
                if (cyclicIndex !== undefined) {
                    residueIndex = cyclicIndex + (residueIndex - this.residueSegmentMax - 1) as ResidueIndex
                } else {
                    residueIndex = this.residueSegmentMax
                }
            }
            const elementIndex = getElementIndexForAtomRole(this.unit.model, residueIndex, atomRole)
            return elementIndex === -1 ? this.residueAtomSegments.offsets[residueIndex] : elementIndex
        }
    
        private setControlPoint(out: Vec3, p1: Vec3, p2: Vec3, p3: Vec3, residueIndex: ResidueIndex) {
            const ss =  this.secondaryStructureType[residueIndex]
            if (SecondaryStructureType.is(ss, SecondaryStructureType.Flag.Beta)) {
                Vec3.scale(out, Vec3.add(out, p1, Vec3.add(out, p3, Vec3.add(out, p2, p2))), 1/4)
            } else {
                Vec3.copy(out, p2)
            }
        }
    
        move() {
            const { residueIt, polymerIt, value } = this
    
            if (this.state === AtomicPolymerTraceIteratorState.nextPolymer) {
                while (polymerIt.hasNext) {
                    this.polymerSegment = polymerIt.move();
                    residueIt.setSegment(this.polymerSegment);
                    this.updateResidueSegmentRange(this.polymerSegment)
                    if (residueIt.hasNext) {
                        this.state = AtomicPolymerTraceIteratorState.nextResidue
                        this.currSecStrucType = SecStrucTypeNA
                        this.nextSecStrucType = this.secondaryStructureType[this.residueSegmentMin]
                        break
                    }
                }
            }
    
            if (this.state === AtomicPolymerTraceIteratorState.nextResidue) {
                const { index: residueIndex } = residueIt.move();
                this.prevSecStrucType = this.currSecStrucType
                this.currSecStrucType = this.nextSecStrucType
                this.nextSecStrucType = residueIt.hasNext ? this.secondaryStructureType[residueIndex + 1] : SecStrucTypeNA
    
                value.secStrucType = this.currSecStrucType
                value.center.element = this.getElementIndex(residueIndex, 'trace')
                value.first = residueIndex === this.residueSegmentMin
                value.last = residueIndex === this.residueSegmentMax
                value.secStrucFirst = this.prevSecStrucType !== this.currSecStrucType
                value.secStrucLast = this.currSecStrucType !== this.nextSecStrucType
                value.moleculeType = getAtomicMoleculeType(this.unit.model, residueIndex)
    
                if (value.first) {
                    this.pos(this.p0, this.getElementIndex(residueIndex - 3 as ResidueIndex, 'trace'))
                    this.pos(this.p1, this.getElementIndex(residueIndex - 2 as ResidueIndex, 'trace'))
                    this.pos(this.p2, this.getElementIndex(residueIndex - 1 as ResidueIndex, 'trace'))
                    this.pos(this.p3, value.center.element)
                    this.pos(this.p4, this.getElementIndex(residueIndex + 1 as ResidueIndex, 'trace'))
                    this.pos(this.p5, this.getElementIndex(residueIndex + 2 as ResidueIndex, 'trace'))
    
                    this.pos(this.v12, this.getElementIndex(residueIndex - 1 as ResidueIndex, 'direction'))
                } else {
                    Vec3.copy(this.p0, this.p1)
                    Vec3.copy(this.p1, this.p2)
                    Vec3.copy(this.p2, this.p3)
                    Vec3.copy(this.p3, this.p4)
                    Vec3.copy(this.p4, this.p5)
                    Vec3.copy(this.p5, this.p6)
    
                    Vec3.copy(this.v12, this.v23)
                }
                this.pos(this.p6, this.getElementIndex(residueIndex + 3 as ResidueIndex, 'trace'))
                this.pos(this.v23, this.getElementIndex(residueIndex, 'direction'))
    
                this.setControlPoint(value.p0, this.p0, this.p1, this.p2, residueIndex - 2 as ResidueIndex)
                this.setControlPoint(value.p1, this.p1, this.p2, this.p3, residueIndex - 1 as ResidueIndex)
                this.setControlPoint(value.p2, this.p2, this.p3, this.p4, residueIndex)
                this.setControlPoint(value.p3, this.p3, this.p4, this.p5, residueIndex + 1 as ResidueIndex)
                this.setControlPoint(value.p4, this.p4, this.p5, this.p6, residueIndex + 2 as ResidueIndex)
    
                Vec3.copy(value.d12, this.v12)
                Vec3.copy(value.d23, this.v23)
    
                if (!residueIt.hasNext) {
                    this.state = AtomicPolymerTraceIteratorState.nextPolymer
                }
            }
    
            this.hasNext = residueIt.hasNext || polymerIt.hasNext
    
            return this.value;
        }
    
        constructor(private unit: Unit.Atomic) {
            this.atomicConformation = unit.model.atomicConformation
            this.residueAtomSegments = unit.model.atomicHierarchy.residueAtomSegments
            this.cyclicPolymerMap = unit.model.atomicHierarchy.cyclicPolymerMap
            this.secondaryStructureType = unit.model.properties.secondaryStructure.type
            this.polymerIt = SortedRanges.transientSegments(getPolymerRanges(unit), unit.elements)
            this.residueIt = Segmentation.transientSegments(this.residueAtomSegments, unit.elements);
            this.value = createPolymerTraceElement(unit)
            this.hasNext = this.residueIt.hasNext && this.polymerIt.hasNext
        }
    }
    
    const enum CoarsePolymerTraceIteratorState { nextPolymer, nextElement }
    
    export class CoarsePolymerTraceIterator implements Iterator<PolymerTraceElement> {
        private value: PolymerTraceElement
        private polymerIt: SortedRanges.Iterator<ElementIndex, ResidueIndex>
        private polymerSegment: Segmentation.Segment<ResidueIndex>
        private state: CoarsePolymerTraceIteratorState = CoarsePolymerTraceIteratorState.nextPolymer
        private conformation: CoarseSphereConformation | CoarseGaussianConformation
        private elementIndex: number
        hasNext: boolean = false;
    
        private pos(target: Vec3, elementIndex: number) {
            elementIndex = Math.min(Math.max(this.polymerSegment.start, elementIndex), this.polymerSegment.end - 1)
            const index = this.unit.elements[elementIndex]
            target[0] = this.conformation.x[index]
            target[1] = this.conformation.y[index]
            target[2] = this.conformation.z[index]
        }
    
        move() {
            if (this.state === CoarsePolymerTraceIteratorState.nextPolymer) {
                while (this.polymerIt.hasNext) {
                    this.polymerSegment = this.polymerIt.move();
                    this.elementIndex = this.polymerSegment.start
    
                    if (this.elementIndex + 1 < this.polymerSegment.end) {
                        this.state = CoarsePolymerTraceIteratorState.nextElement
                        break
                    }
                }
            }
    
            if (this.state === CoarsePolymerTraceIteratorState.nextElement) {
                this.elementIndex += 1
                this.value.center.element = this.value.center.unit.elements[this.elementIndex]
    
                this.pos(this.value.p0, this.elementIndex - 2)
                this.pos(this.value.p1, this.elementIndex - 1)
                this.pos(this.value.p2, this.elementIndex)
                this.pos(this.value.p3, this.elementIndex + 1)
                this.pos(this.value.p4, this.elementIndex + 2)
    
                this.value.first = this.elementIndex === this.polymerSegment.start
                this.value.last = this.elementIndex === this.polymerSegment.end - 1
    
                if (this.elementIndex + 1 >= this.polymerSegment.end) {
                    this.state = CoarsePolymerTraceIteratorState.nextPolymer
                }
            }
    
            this.hasNext = this.elementIndex + 1 < this.polymerSegment.end || this.polymerIt.hasNext
            return this.value;
        }
    
        constructor(private unit: Unit.Spheres | Unit.Gaussians) {
            this.polymerIt = SortedRanges.transientSegments(getPolymerRanges(unit), unit.elements);
            this.value = createPolymerTraceElement(unit)
            switch (unit.kind) {
                case Unit.Kind.Spheres: this.conformation = unit.model.coarseConformation.spheres; break
                case Unit.Kind.Gaussians: this.conformation = unit.model.coarseConformation.gaussians; break
            }
            this.hasNext = this.polymerIt.hasNext
        }
    }