diff --git a/.vscode/extensions.json b/.vscode/extensions.json new file mode 100644 index 0000000000000000000000000000000000000000..66b79079c93dc16fb531d184ab087fd311607b28 --- /dev/null +++ b/.vscode/extensions.json @@ -0,0 +1,14 @@ +{ + // See http://go.microsoft.com/fwlink/?LinkId=827846 to learn about workspace recommendations. + // Extension identifier format: ${publisher}.${name}. Example: vscode.csharp + + // List of extensions which should be recommended for users of this workspace. + "recommendations": [ + "ms-vscode.vscode-typescript-tslint-plugin", + "slevesque.shader" + ], + // List of extensions recommended by VS Code that should not be recommended for users of this workspace. + "unwantedRecommendations": [ + + ] +} \ No newline at end of file diff --git a/src/mol-math/linear-algebra/3d/quat.ts b/src/mol-math/linear-algebra/3d/quat.ts index 2642c145c4b437c92f35a76d86177c9c0c3ff04d..569dc63735aae842b58d80837d1e3721c8fc9e81 100644 --- a/src/mol-math/linear-algebra/3d/quat.ts +++ b/src/mol-math/linear-algebra/3d/quat.ts @@ -435,6 +435,10 @@ namespace Quat { return normalize(out, Quat.fromMat3(out, axesTmpMat)); } + + export function toString(a: Quat, precision?: number) { + return `[${a[0].toPrecision(precision)} ${a[1].toPrecision(precision)} ${a[2].toPrecision(precision)} ${a[3].toPrecision(precision)}]`; + } } export default Quat \ No newline at end of file diff --git a/src/mol-math/linear-algebra/3d/vec2.ts b/src/mol-math/linear-algebra/3d/vec2.ts index 3a5785dcffcf41bef5268369fc4ee6014c5c17a3..d1bd980551e856fc5f5e0c699636146776a7eac1 100644 --- a/src/mol-math/linear-algebra/3d/vec2.ts +++ b/src/mol-math/linear-algebra/3d/vec2.ts @@ -166,6 +166,10 @@ namespace Vec2 { export function areEqual(a: Vec2, b: Vec2) { return a[0] === b[0] && a[1] === b[1]; } + + export function toString(a: Vec2, precision?: number) { + return `[${a[0].toPrecision(precision)} ${a[1].toPrecision(precision)}}]`; + } } export default Vec2 \ No newline at end of file diff --git a/src/mol-math/linear-algebra/3d/vec3.ts b/src/mol-math/linear-algebra/3d/vec3.ts index a8bae39359b0be356ffce17e05559bf11a693280..b50d947b165eb1a9cb7b887b520a9cac304f7b19 100644 --- a/src/mol-math/linear-algebra/3d/vec3.ts +++ b/src/mol-math/linear-algebra/3d/vec3.ts @@ -19,7 +19,7 @@ import Mat4 from './mat4'; import { Quat, Mat3, EPSILON } from '../3d'; -import { spline as _spline, clamp } from '../../interpolate' +import { spline as _spline, quadraticBezier as _quadraticBezier, clamp } from '../../interpolate' import { NumberArray } from '../../../mol-util/type-helpers'; interface Vec3 extends Array<number> { [d: number]: number, '@type': 'vec3', length: 3 } @@ -344,6 +344,14 @@ namespace Vec3 { return out; } + export function quadraticBezier(out: Vec3, a: Vec3, b: Vec3, c: Vec3, t: number) { + out[0] = _quadraticBezier(a[0], b[0], c[0], t); + out[1] = _quadraticBezier(a[1], b[1], c[1], t); + out[2] = _quadraticBezier(a[2], b[2], c[2], t); + + return out; + } + /** * Performs a spline interpolation with two control points and a tension parameter */ @@ -525,8 +533,8 @@ namespace Vec3 { return normalize(out, cross(out, triangleNormalTmpAB, triangleNormalTmpAC)); } - export function toString(a: Vec3) { - return `[${a[0]} ${a[1]} ${a[2]}]`; + export function toString(a: Vec3, precision?: number) { + return `[${a[0].toPrecision(precision)} ${a[1].toPrecision(precision)} ${a[2].toPrecision(precision)}]`; } } diff --git a/src/mol-math/linear-algebra/3d/vec4.ts b/src/mol-math/linear-algebra/3d/vec4.ts index 80672cf6e9cd84d77f09d92e93517410a9c3dd46..753356f0c80ef3650fc3f108404a782a87b447f4 100644 --- a/src/mol-math/linear-algebra/3d/vec4.ts +++ b/src/mol-math/linear-algebra/3d/vec4.ts @@ -225,6 +225,10 @@ namespace Vec4 { Math.abs(a2 - b2) <= EPSILON.Value * Math.max(1.0, Math.abs(a2), Math.abs(b2)) && Math.abs(a3 - b3) <= EPSILON.Value * Math.max(1.0, Math.abs(a3), Math.abs(b3))); } + + export function toString(a: Vec4, precision?: number) { + return `[${a[0].toPrecision(precision)} ${a[1].toPrecision(precision)} ${a[2].toPrecision(precision)} ${a[3].toPrecision(precision)}]`; + } } export default Vec4 \ No newline at end of file diff --git a/src/mol-model/structure/model/properties/atomic/hierarchy.ts b/src/mol-model/structure/model/properties/atomic/hierarchy.ts index 0854b3b13fa485b18a100648b271f93ebf317da1..1c12b0be4b5b549f0106350851a60ded5ad2aee6 100644 --- a/src/mol-model/structure/model/properties/atomic/hierarchy.ts +++ b/src/mol-model/structure/model/properties/atomic/hierarchy.ts @@ -1,5 +1,5 @@ /** - * Copyright (c) 2017-2018 mol* contributors, licensed under MIT, See LICENSE file for more info. + * Copyright (c) 2017-2019 mol* contributors, licensed under MIT, See LICENSE file for more info. * * @author David Sehnal <david.sehnal@gmail.com> * @author Alexander Rose <alexander.rose@weirdbyte.de> @@ -113,7 +113,8 @@ export interface AtomicData { export interface AtomicDerivedData { readonly residue: { readonly traceElementIndex: ArrayLike<ElementIndex | -1> - readonly directionElementIndex: ArrayLike<ElementIndex | -1> + readonly directionFromElementIndex: ArrayLike<ElementIndex | -1> + readonly directionToElementIndex: ArrayLike<ElementIndex | -1> readonly moleculeType: ArrayLike<MoleculeType> } } diff --git a/src/mol-model/structure/model/properties/utils/atomic-derived.ts b/src/mol-model/structure/model/properties/utils/atomic-derived.ts index 67f3a8a10bc30b3dacc1601e4457925d07056582..11706d5ada50c1cab3eb8459e681e444d347908d 100644 --- a/src/mol-model/structure/model/properties/utils/atomic-derived.ts +++ b/src/mol-model/structure/model/properties/utils/atomic-derived.ts @@ -15,7 +15,8 @@ export function getAtomicDerivedData(data: AtomicData, index: AtomicIndex, chemi const { label_comp_id, _rowCount: n } = data.residues const traceElementIndex = new Int32Array(n) - const directionElementIndex = new Int32Array(n) + const directionFromElementIndex = new Int32Array(n) + const directionToElementIndex = new Int32Array(n) const moleculeType = new Uint8Array(n) const moleculeTypeMap = new Map<string, MoleculeType>() @@ -44,14 +45,18 @@ export function getAtomicDerivedData(data: AtomicData, index: AtomicIndex, chemi } traceElementIndex[i] = traceIndex - const directionAtomId = getAtomIdForAtomRole(molType, 'direction') - directionElementIndex[i] = index.findAtomsOnResidue(i as ResidueIndex, directionAtomId) + const directionFromAtomId = getAtomIdForAtomRole(molType, 'directionFrom') + directionFromElementIndex[i] = index.findAtomsOnResidue(i as ResidueIndex, directionFromAtomId) + + const directionToAtomId = getAtomIdForAtomRole(molType, 'directionTo') + directionToElementIndex[i] = index.findAtomsOnResidue(i as ResidueIndex, directionToAtomId) } return { residue: { traceElementIndex: traceElementIndex as unknown as ArrayLike<ElementIndex | -1>, - directionElementIndex: directionElementIndex as unknown as ArrayLike<ElementIndex | -1>, + directionFromElementIndex: directionFromElementIndex as unknown as ArrayLike<ElementIndex | -1>, + directionToElementIndex: directionToElementIndex as unknown as ArrayLike<ElementIndex | -1>, moleculeType: moleculeType as unknown as ArrayLike<MoleculeType>, } } diff --git a/src/mol-model/structure/model/types.ts b/src/mol-model/structure/model/types.ts index 89eaf3b4a058e2957e804f517599dcd4c6e4bb70..a41c0d419dd1bd495b362444be3c97104dd3b3d7 100644 --- a/src/mol-model/structure/model/types.ts +++ b/src/mol-model/structure/model/types.ts @@ -59,33 +59,37 @@ export const enum MoleculeType { saccharide } -export type AtomRole = 'trace' | 'direction' | 'backboneStart' | 'backboneEnd' | 'coarseBackbone' +export type AtomRole = 'trace' | 'directionFrom' | 'directionTo' | 'backboneStart' | 'backboneEnd' | 'coarseBackbone' export const MoleculeTypeAtomRoleId: { [k: number]: { [k in AtomRole]: Set<string> } } = { [MoleculeType.protein]: { trace: new Set(['CA']), - direction: new Set(['O', 'OC1', 'O1', 'OX1', 'OXT']), + directionFrom: new Set(['C']), + directionTo: new Set(['O', 'OC1', 'O1', 'OX1', 'OXT']), backboneStart: new Set(['N']), backboneEnd: new Set(['C']), coarseBackbone: new Set(['CA', 'BB']) }, [MoleculeType.RNA]: { trace: new Set(['C4\'', 'C4*']), - direction: new Set(['C3\'', 'C3*']), + directionFrom: new Set(['C4\'', 'C4*']), + directionTo: new Set(['C3\'', 'C3*']), backboneStart: new Set(['P']), backboneEnd: new Set(['O3\'', 'O3*']), coarseBackbone: new Set(['P']) }, [MoleculeType.DNA]: { trace: new Set(['C3\'', 'C3*']), - direction: new Set(['C1\'', 'C1*']), + directionFrom: new Set(['C3\'', 'C3*']), + directionTo: new Set(['C1\'', 'C1*']), backboneStart: new Set(['P']), backboneEnd: new Set(['O3\'', 'O3*']), coarseBackbone: new Set(['P']) }, [MoleculeType.PNA]: { trace: new Set(['N4\'', 'N4*']), - direction: new Set(['C7\'', 'C7*']), + directionFrom: new Set(['N4\'', 'N4*']), + directionTo: new Set(['C7\'', 'C7*']), backboneStart: new Set(['N1\'', 'N1*']), backboneEnd: new Set(['C\'', 'C*']), coarseBackbone: new Set(['P']) diff --git a/src/mol-repr/structure/visual/polymer-trace-mesh.ts b/src/mol-repr/structure/visual/polymer-trace-mesh.ts index 16793765b52f454f5123e5a972128dcd30bf43ae..4c94290bbc7b2f920e05ce61bc1e47e6600f8fa4 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 b096422dcab5a3eab1771bd0c61475c14c9a1eaf..ebb7aaf3d2a5ab65d1f7e6c1f8e7472801bd2dfb 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 c731071615a795d4c00b7c34ef8ee104eaadbefb..c510f7c3b61ea818b3561948d2156aa23dc60c41 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)