From 9b3d2f396efc658b84d50b8aab948cbb51812f4c Mon Sep 17 00:00:00 2001 From: Alexander Rose <alexander.rose@weirdbyte.de> Date: Wed, 12 Jun 2019 23:14:05 -0700 Subject: [PATCH] polymer-trace improvements --- .../structure/visual/polymer-trace-mesh.ts | 2 +- .../visual/util/polymer/curve-segment.ts | 50 ++++++------- .../visual/util/polymer/trace-iterator.ts | 71 ++++++++++++------- 3 files changed, 74 insertions(+), 49 deletions(-) diff --git a/src/mol-repr/structure/visual/polymer-trace-mesh.ts b/src/mol-repr/structure/visual/polymer-trace-mesh.ts index 16793765b..4c94290bb 100644 --- a/src/mol-repr/structure/visual/polymer-trace-mesh.ts +++ b/src/mol-repr/structure/visual/polymer-trace-mesh.ts @@ -52,7 +52,7 @@ function createPolymerTraceMesh(ctx: VisualContext, unit: Unit, structure: Struc const isNucleicType = isNucleic(v.moleculeType) const isSheet = SecondaryStructureType.is(v.secStrucType, SecondaryStructureType.Flag.Beta) const isHelix = SecondaryStructureType.is(v.secStrucType, SecondaryStructureType.Flag.Helix) - const tension = isNucleicType ? 0.5 : 0.9 + const tension = isHelix ? 0.9 : 0.5 const shift = isNucleicType ? 0.3 : 0.5 interpolateCurveSegment(state, v, tension, shift) diff --git a/src/mol-repr/structure/visual/util/polymer/curve-segment.ts b/src/mol-repr/structure/visual/util/polymer/curve-segment.ts index b096422dc..ebb7aaf3d 100644 --- a/src/mol-repr/structure/visual/util/polymer/curve-segment.ts +++ b/src/mol-repr/structure/visual/util/polymer/curve-segment.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> */ @@ -19,6 +19,7 @@ export interface CurveSegmentState { } export interface CurveSegmentControls { + secStrucFirst: boolean, secStrucLast: boolean p0: Vec3, p1: Vec3, p2: Vec3, p3: Vec3, p4: Vec3, d12: Vec3, d23: Vec3 } @@ -48,20 +49,25 @@ const curvePoint = Vec3.zero() export function interpolatePointsAndTangents(state: CurveSegmentState, controls: CurveSegmentControls, tension: number, shift: number) { const { curvePoints, tangentVectors, linearSegments } = state - const { p0, p1, p2, p3, p4 } = controls + const { p0, p1, p2, p3, p4, secStrucFirst, secStrucLast } = controls const shift1 = 1 - shift + const tensionBeg = secStrucFirst ? 0.5 : tension + const tensionEnd = secStrucLast ? 0.5 : tension + for (let j = 0; j <= linearSegments; ++j) { const t = j * 1.0 / linearSegments; if (t < shift1) { - Vec3.spline(curvePoint, p0, p1, p2, p3, t + shift, tension) - Vec3.spline(tanA, p0, p1, p2, p3, t + shift + 0.01, tension) - Vec3.spline(tanB, p0, p1, p2, p3, t + shift - 0.01, tension) + const te = lerp(tensionBeg, tension, t) + Vec3.spline(curvePoint, p0, p1, p2, p3, t + shift, te) + Vec3.spline(tanA, p0, p1, p2, p3, t + shift + 0.01, tensionBeg) + Vec3.spline(tanB, p0, p1, p2, p3, t + shift - 0.01, tensionBeg) } else { - Vec3.spline(curvePoint, p1, p2, p3, p4, t - shift1, tension) - Vec3.spline(tanA, p1, p2, p3, p4, t - shift1 + 0.01, tension) - Vec3.spline(tanB, p1, p2, p3, p4, t - shift1 - 0.01, tension) + const te = lerp(tension, tensionEnd, t) + Vec3.spline(curvePoint, p1, p2, p3, p4, t - shift1, te) + Vec3.spline(tanA, p1, p2, p3, p4, t - shift1 + 0.01, te) + Vec3.spline(tanB, p1, p2, p3, p4, t - shift1 - 0.01, te) } Vec3.toArray(curvePoint, curvePoints, j * 3) Vec3.normalize(tangentVec, Vec3.sub(tangentVec, tanA, tanB)) @@ -69,17 +75,15 @@ export function interpolatePointsAndTangents(state: CurveSegmentState, controls: } } -const tmpNormal = Vec3.zero() -const tangentVec = Vec3.zero() -const normalVec = Vec3.zero() -const binormalVec = Vec3.zero() -const prevNormal = Vec3.zero() -const firstControlPoint = Vec3.zero() -const lastControlPoint = Vec3.zero() -const firstTangentVec = Vec3.zero() -const lastTangentVec = Vec3.zero() -const firstNormalVec = Vec3.zero() -const lastNormalVec = Vec3.zero() +const tmpNormal = Vec3() +const tangentVec = Vec3() +const normalVec = Vec3() +const binormalVec = Vec3() +const prevNormal = Vec3() +const firstTangentVec = Vec3() +const lastTangentVec = Vec3() +const firstNormalVec = Vec3() +const lastNormalVec = Vec3() /** * Populate normalVectors by interpolating from firstDirection to lastDirection with @@ -91,13 +95,11 @@ export function interpolateNormals(state: CurveSegmentState, controls: CurveSegm const n = curvePoints.length / 3 - Vec3.fromArray(firstControlPoint, curvePoints, 0) - Vec3.fromArray(lastControlPoint, curvePoints, (n - 1) * 3) Vec3.fromArray(firstTangentVec, tangentVectors, 0) - Vec3.fromArray(lastTangentVec, tangentVectors, (n - 1) * 3) + Vec3.fromArray(lastTangentVec, tangentVectors, (n - 1) * 3) - Vec3.orthogonalize(firstNormalVec, firstTangentVec, Vec3.sub(tmpNormal, firstControlPoint, firstDirection)) - Vec3.orthogonalize(lastNormalVec, lastTangentVec, Vec3.sub(tmpNormal, lastControlPoint, lastDirection)) + Vec3.orthogonalize(firstNormalVec, firstTangentVec, firstDirection) + Vec3.orthogonalize(lastNormalVec, lastTangentVec, lastDirection) if (Vec3.dot(firstNormalVec, lastNormalVec) < 0) { Vec3.scale(lastNormalVec, lastNormalVec, -1) diff --git a/src/mol-repr/structure/visual/util/polymer/trace-iterator.ts b/src/mol-repr/structure/visual/util/polymer/trace-iterator.ts index c73107161..c510f7c3b 100644 --- a/src/mol-repr/structure/visual/util/polymer/trace-iterator.ts +++ b/src/mol-repr/structure/visual/util/polymer/trace-iterator.ts @@ -57,13 +57,16 @@ function createPolymerTraceElement (unit: Unit): PolymerTraceElement { moleculeType: MoleculeType.unknown, coarseBackboneFirst: false, coarseBackboneLast: false, isCoarseBackbone: false, - 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), + p0: Vec3(), p1: Vec3(), p2: Vec3(), p3: Vec3(), p4: Vec3(), + d12: Vec3(), d23: Vec3() } } const enum AtomicPolymerTraceIteratorState { nextPolymer, nextResidue } +const tmpVecA = Vec3() +const tmpVecB = Vec3() + export class AtomicPolymerTraceIterator implements Iterator<PolymerTraceElement> { private value: PolymerTraceElement private polymerIt: SortedRanges.Iterator<ElementIndex, ResidueIndex> @@ -83,22 +86,23 @@ export class AtomicPolymerTraceIterator implements Iterator<PolymerTraceElement> private state: AtomicPolymerTraceIteratorState = AtomicPolymerTraceIteratorState.nextPolymer private residueAtomSegments: Segmentation<ElementIndex, ResidueIndex> private traceElementIndex: ArrayLike<ElementIndex> - private directionElementIndex: ArrayLike<ElementIndex | -1> + private directionFromElementIndex: ArrayLike<ElementIndex | -1> + private directionToElementIndex: ArrayLike<ElementIndex | -1> private moleculeType: ArrayLike<MoleculeType> 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 p0 = Vec3() + private p1 = Vec3() + private p2 = Vec3() + private p3 = Vec3() + private p4 = Vec3() + private p5 = Vec3() + private p6 = Vec3() - // private v01 = Vec3.zero(); - private v12 = Vec3.create(1, 0, 0); - private v23 = Vec3.create(1, 0, 0); - // private v34 = Vec3.zero(); + private d01 = Vec3() + private d12 = Vec3() + private d23 = Vec3() + private d34 = Vec3() hasNext: boolean = false; @@ -148,6 +152,20 @@ export class AtomicPolymerTraceIterator implements Iterator<PolymerTraceElement> } } + private setFromToVector(out: Vec3, residueIndex: ResidueIndex) { + this.pos(tmpVecA, this.directionFromElementIndex[residueIndex]) + this.pos(tmpVecB, this.directionToElementIndex[residueIndex]) + Vec3.sub(out, tmpVecB, tmpVecA) + } + + private setDirection(out: Vec3, v1: Vec3, v2: Vec3, v3: Vec3) { + Vec3.copy(tmpVecA, v1) + Vec3.copy(tmpVecB, v3) + if (Vec3.dot(v2, tmpVecA) < 0) Vec3.scale(tmpVecA, tmpVecA, -1) + if (Vec3.dot(v2, tmpVecB) < 0) Vec3.scale(tmpVecB, tmpVecB, -1) + Vec3.scale(out, Vec3.add(out, tmpVecA, Vec3.add(out, tmpVecB, Vec3.add(out, v2, v2))), 1/4) + } + move() { const { residueIt, polymerIt, value } = this @@ -161,7 +179,7 @@ export class AtomicPolymerTraceIterator implements Iterator<PolymerTraceElement> this.currSecStrucType = SecStrucTypeNA this.nextSecStrucType = this.getSecStruc(this.residueSegmentMin) this.currCoarseBackbone = false - this.nextCoarseBackbone = this.directionElementIndex[this.residueSegmentMin] === -1 + this.nextCoarseBackbone = this.directionFromElementIndex[this.residueSegmentMin] === -1 || this.directionToElementIndex[this.residueSegmentMin] === -1 break } } @@ -175,7 +193,7 @@ export class AtomicPolymerTraceIterator implements Iterator<PolymerTraceElement> this.prevCoarseBackbone = this.currCoarseBackbone this.currCoarseBackbone = this.nextCoarseBackbone - this.nextCoarseBackbone = residueIt.hasNext ? this.directionElementIndex[residueIndex + 1] === -1 : false + this.nextCoarseBackbone = residueIt.hasNext ? (this.directionFromElementIndex[residueIndex + 1] === -1 || this.directionToElementIndex[residueIndex + 1] === -1) : false value.secStrucType = this.currSecStrucType value.secStrucFirst = this.prevSecStrucType !== this.currSecStrucType @@ -205,7 +223,9 @@ export class AtomicPolymerTraceIterator implements Iterator<PolymerTraceElement> this.pos(this.p4, this.traceElementIndex[residueIndexNext1]) this.pos(this.p5, this.traceElementIndex[residueIndexNext2]) - this.pos(this.v12, this.directionElementIndex[residueIndexPrev1]) + this.setFromToVector(this.d01, residueIndexPrev1) + this.setFromToVector(this.d12, residueIndex) + this.setFromToVector(this.d23, residueIndexNext1) } else { value.centerPrev.element = value.center.element value.center.element = value.centerNext.element @@ -217,12 +237,14 @@ export class AtomicPolymerTraceIterator implements Iterator<PolymerTraceElement> Vec3.copy(this.p4, this.p5) Vec3.copy(this.p5, this.p6) - Vec3.copy(this.v12, this.v23) + Vec3.copy(this.d01, this.d12) + Vec3.copy(this.d12, this.d23) + Vec3.copy(this.d23, this.d34) } value.centerNext.element = this.traceElementIndex[residueIndexNext1] - this.pos(this.p6, this.traceElementIndex[residueIndexNext3]) - this.pos(this.v23, this.directionElementIndex[residueIndex]) - value.isCoarseBackbone = this.directionElementIndex[residueIndex] === -1 + this.pos(this.p6, this.traceElementIndex[residueIndexNext3]) + this.setFromToVector(this.d34, residueIndexNext2) + value.isCoarseBackbone = this.directionFromElementIndex[residueIndex] === -1 || this.directionToElementIndex[residueIndex] === -1 this.setControlPoint(value.p0, this.p0, this.p1, this.p2, residueIndexPrev2) this.setControlPoint(value.p1, this.p1, this.p2, this.p3, residueIndexPrev1) @@ -230,8 +252,8 @@ export class AtomicPolymerTraceIterator implements Iterator<PolymerTraceElement> this.setControlPoint(value.p3, this.p3, this.p4, this.p5, residueIndexNext1) this.setControlPoint(value.p4, this.p4, this.p5, this.p6, residueIndexNext2) - Vec3.copy(value.d12, this.v12) - Vec3.copy(value.d23, this.v23) + this.setDirection(value.d12, this.d01, this.d12, this.d23) + this.setDirection(value.d23, this.d12, this.d23, this.d34) if (!residueIt.hasNext) { this.state = AtomicPolymerTraceIteratorState.nextPolymer @@ -247,7 +269,8 @@ export class AtomicPolymerTraceIterator implements Iterator<PolymerTraceElement> this.atomicConformation = unit.model.atomicConformation this.residueAtomSegments = unit.model.atomicHierarchy.residueAtomSegments this.traceElementIndex = unit.model.atomicHierarchy.derived.residue.traceElementIndex as ArrayLike<ElementIndex> // can assume it won't be -1 for polymer residues - this.directionElementIndex = unit.model.atomicHierarchy.derived.residue.directionElementIndex + this.directionFromElementIndex = unit.model.atomicHierarchy.derived.residue.directionFromElementIndex + this.directionToElementIndex = unit.model.atomicHierarchy.derived.residue.directionToElementIndex this.moleculeType = unit.model.atomicHierarchy.derived.residue.moleculeType this.cyclicPolymerMap = unit.model.atomicHierarchy.cyclicPolymerMap this.polymerIt = SortedRanges.transientSegments(getPolymerRanges(unit), unit.elements) -- GitLab