Browse Source

added sheet geometry

Alexander Rose 6 years ago
parent
commit
34695dc7e7

+ 115 - 0
src/mol-geo/primitive/sheet.ts

@@ -0,0 +1,115 @@
+/**
+ * Copyright (c) 2018 mol* contributors, licensed under MIT, See LICENSE file for more info.
+ *
+ * @author Alexander Rose <alexander.rose@weirdbyte.de>
+ * @author David Sehnal <david.sehnal@gmail.com>
+ */
+
+import { Vec3 } from 'mol-math/linear-algebra';
+import { ChunkedArray } from 'mol-data/util';
+
+const tA = Vec3.zero()
+const tB = Vec3.zero()
+const tV = Vec3.zero()
+
+const horizontalVector = Vec3.zero()
+const verticalVector = Vec3.zero()
+const normalOffset = Vec3.zero()
+const positionVector = Vec3.zero()
+const normalVector = Vec3.zero()
+const torsionVector = Vec3.zero()
+
+export function addSheet(controlPoints: Helpers.NumberArray, normalVectors: Helpers.NumberArray, binormalVectors: Helpers.NumberArray, linearSegments: number, width: number, height: number, arrowWidth: number, vertices: ChunkedArray<number, 3>, normals: ChunkedArray<number, 3>, indices: ChunkedArray<number, 3>, ids: ChunkedArray<number, 1>, currentId: number) {
+
+    const vertexCount = vertices.elementCount
+    let offsetLength = 0
+
+    if (arrowWidth > 0) {
+        Vec3.fromArray(tA, controlPoints, 0)
+        Vec3.fromArray(tB, controlPoints, linearSegments * 3)
+        offsetLength = arrowWidth / Vec3.magnitude(Vec3.sub(tV, tB, tA))
+    }
+
+    for (let i = 0; i <= linearSegments; ++i) {
+        const actualWidth = arrowWidth === 0 ? width : arrowWidth * (1 - i / linearSegments);
+
+        const i3 = i * 3
+
+        Vec3.fromArray(verticalVector, normalVectors, i3)
+        Vec3.scale(verticalVector, verticalVector, actualWidth);
+
+        Vec3.fromArray(horizontalVector, binormalVectors, i3)
+        Vec3.scale(horizontalVector, horizontalVector, height);
+
+        if (arrowWidth > 0) {
+            Vec3.fromArray(tA, normalVectors, i3)
+            Vec3.fromArray(tB, binormalVectors, i3)
+            Vec3.scale(normalOffset, Vec3.cross(normalOffset, tA, tB), offsetLength)
+        }
+
+        Vec3.fromArray(positionVector, controlPoints, i3)
+        Vec3.fromArray(normalVector, normalVectors, i3)
+        Vec3.fromArray(torsionVector, binormalVectors, i3)
+
+        Vec3.add(tA, Vec3.add(tA, Vec3.copy(tA, positionVector), horizontalVector), verticalVector)
+        Vec3.copy(tB, normalVector)
+        ChunkedArray.add3(vertices, tA[0], tA[1], tA[2])
+        ChunkedArray.add3(normals, tB[0], tB[1], tB[2])
+        ChunkedArray.add(ids, currentId);
+
+        Vec3.add(tA, Vec3.sub(tA, Vec3.copy(tA, positionVector), horizontalVector), verticalVector)
+        ChunkedArray.add3(vertices, tA[0], tA[1], tA[2])
+        ChunkedArray.add3(normals, tB[0], tB[1], tB[2])
+        ChunkedArray.add(ids, currentId);
+
+        Vec3.add(tA, Vec3.sub(tA, Vec3.copy(tA, positionVector), horizontalVector), verticalVector)
+        Vec3.add(tB, Vec3.scale(tB, Vec3.copy(tB, torsionVector), -1), normalOffset)
+        ChunkedArray.add3(vertices, tA[0], tA[1], tA[2])
+        ChunkedArray.add3(normals, tB[0], tB[1], tB[2])
+        ChunkedArray.add(ids, currentId);
+
+        Vec3.sub(tA, Vec3.sub(tA, Vec3.copy(tA, positionVector), horizontalVector), verticalVector)
+        ChunkedArray.add3(vertices, tA[0], tA[1], tA[2])
+        ChunkedArray.add3(normals, tB[0], tB[1], tB[2])
+        ChunkedArray.add(ids, currentId);
+
+        Vec3.sub(tA, Vec3.sub(tA, Vec3.copy(tA, positionVector), horizontalVector), verticalVector)
+        Vec3.scale(tB, Vec3.copy(tB, normalVector), -1)
+        ChunkedArray.add3(vertices, tA[0], tA[1], tA[2])
+        ChunkedArray.add3(normals, tB[0], tB[1], tB[2])
+        ChunkedArray.add(ids, currentId);
+
+        Vec3.sub(tA, Vec3.add(tA, Vec3.copy(tA, positionVector), horizontalVector), verticalVector)
+        ChunkedArray.add3(vertices, tA[0], tA[1], tA[2])
+        ChunkedArray.add3(normals, tB[0], tB[1], tB[2])
+        ChunkedArray.add(ids, currentId);
+
+        Vec3.sub(tA, Vec3.add(tA, Vec3.copy(tA, positionVector), horizontalVector), verticalVector)
+        Vec3.add(tB, Vec3.copy(tB, torsionVector), normalOffset)
+        ChunkedArray.add3(vertices, tA[0], tA[1], tA[2])
+        ChunkedArray.add3(normals, tB[0], tB[1], tB[2])
+        ChunkedArray.add(ids, currentId);
+
+        Vec3.add(tA, Vec3.add(tA, Vec3.copy(tA, positionVector), horizontalVector), verticalVector)
+        ChunkedArray.add3(vertices, tA[0], tA[1], tA[2])
+        ChunkedArray.add3(normals, tB[0], tB[1], tB[2])
+        ChunkedArray.add(ids, currentId);
+    }
+
+    for (let i = 0; i < linearSegments; ++i) {
+        for (let j = 0; j < 4; j++) {
+            ChunkedArray.add3(
+                indices,
+                vertexCount + i * 8 + 2 * j,
+                vertexCount + (i + 1) * 8 + 2 * j + 1,
+                vertexCount + i * 8 + 2 * j + 1
+            );
+            ChunkedArray.add3(
+                indices,
+                vertexCount + i * 8 + 2 * j,
+                vertexCount + (i + 1) * 8 + 2 * j,
+                vertexCount + (i + 1) * 8 + 2 * j + 1
+            );
+        }
+    }
+}

+ 77 - 0
src/mol-geo/primitive/tube.ts

@@ -0,0 +1,77 @@
+/**
+ * Copyright (c) 2018 mol* contributors, licensed under MIT, See LICENSE file for more info.
+ *
+ * @author Alexander Rose <alexander.rose@weirdbyte.de>
+ * @author David Sehnal <david.sehnal@gmail.com>
+ */
+
+import { Vec3 } from 'mol-math/linear-algebra';
+import { ChunkedArray } from 'mol-data/util';
+
+const normalVector = Vec3.zero()
+const binormalVector = Vec3.zero()
+const tempPos = Vec3.zero()
+const a = Vec3.zero()
+const b = Vec3.zero()
+const u = Vec3.zero()
+const v = Vec3.zero()
+
+export function addTube(controlPoints: Helpers.NumberArray, normalVectors: Helpers.NumberArray, binormalVectors: Helpers.NumberArray, linearSegments: number, radialSegments: number, width: number, height: number, waveFactor: number, vertices: ChunkedArray<number, 3>, normals: ChunkedArray<number, 3>, indices: ChunkedArray<number, 3>, ids: ChunkedArray<number, 1>, currentId: number) {
+    const vertexCount = vertices.elementCount
+    const di = 1 / linearSegments
+
+    for (let i = 0; i <= linearSegments; ++i) {
+        const i3 = i * 3
+        Vec3.fromArray(u, normalVectors, i3)
+        Vec3.fromArray(v, binormalVectors, i3)
+
+        const tt = di * i - 0.5;
+        const ff = 1 + (waveFactor - 1) * (Math.cos(2 * Math.PI * tt) + 1);
+        const w = ff * width, h = ff * height;
+
+        for (let j = 0; j < radialSegments; ++j) {
+            let t = 2 * Math.PI * j / radialSegments;
+
+            Vec3.copy(a, u)
+            Vec3.copy(b, v)
+            Vec3.add(
+                normalVector,
+                Vec3.scale(a, a, w * Math.cos(t)),
+                Vec3.scale(b, b, h * Math.sin(t))
+            )
+
+            Vec3.copy(a, u)
+            Vec3.copy(b, v)
+            Vec3.add(
+                binormalVector,
+                Vec3.scale(a, a, h * Math.cos(t)),
+                Vec3.scale(b, b, w * Math.sin(t))
+            )
+            Vec3.normalize(normalVector, normalVector)
+
+            Vec3.fromArray(tempPos, controlPoints, i3)
+            Vec3.add(tempPos, tempPos, binormalVector)
+
+            ChunkedArray.add3(vertices, tempPos[0], tempPos[1], tempPos[2]);
+            ChunkedArray.add3(normals, normalVector[0], normalVector[1], normalVector[2]);
+            ChunkedArray.add(ids, currentId);
+        }
+    }
+
+    for (let i = 0; i < linearSegments; ++i) {
+        for (let j = 0; j < radialSegments; ++j) {
+            ChunkedArray.add3(
+                indices,
+                (vertexCount + i * radialSegments + (j + 1) % radialSegments),
+                (vertexCount + (i + 1) * radialSegments + (j + 1) % radialSegments),
+                (vertexCount + i * radialSegments + j)
+            );
+            ChunkedArray.add3(
+                indices,
+                (vertexCount + (i + 1) * radialSegments + (j + 1) % radialSegments),
+                (vertexCount + (i + 1) * radialSegments + j),
+                (vertexCount + i * radialSegments + j)
+            );
+        }
+    }
+}

+ 11 - 10
src/mol-geo/representation/structure/visual/polymer-trace-mesh.ts

@@ -187,18 +187,19 @@ async function createPolymerTraceMesh(ctx: RuntimeContext, unit: Unit, mesh?: Me
         // builder.addIcosahedron(v.t3, 0.25, 1)
         // builder.addIcosahedron(v.t4, 0.25, 1)
 
-        let width = 0.2
-        let height = 0.2
-        if (
-            SecondaryStructureType.is(v.secStrucType, SecondaryStructureType.Flag.Beta) ||
-            SecondaryStructureType.is(v.secStrucType, SecondaryStructureType.Flag.Helix)
-        ) {
-            width = 0.1
-            height = 0.8
-        }
+        let width = 0.2, height = 0.2
 
         // TODO size theme
-        builder.addTube(controlPoints, normalVectors, binormalVectors, linearSegments, radialSegments, width, height, 1)
+        if (SecondaryStructureType.is(v.secStrucType, SecondaryStructureType.Flag.Beta)) {
+            width = 1.0; height = 0.15
+            const arrowWidth = v.secStrucChange ? 1.7 : 0
+            builder.addSheet(controlPoints, normalVectors, binormalVectors, linearSegments, width, height, arrowWidth)
+        } else {
+            if (SecondaryStructureType.is(v.secStrucType, SecondaryStructureType.Flag.Helix)) {
+                width = 0.2; height = 1.0
+            }
+            builder.addTube(controlPoints, normalVectors, binormalVectors, linearSegments, radialSegments, width, height, 1)
+        }
 
         if (i % 10000 === 0 && ctx.shouldUpdate) {
             await ctx.update({ message: 'Polymer trace mesh', current: i, max: polymerElementCount });

+ 26 - 21
src/mol-geo/representation/structure/visual/util/polymer.ts

@@ -132,7 +132,7 @@ export class AtomicPolymerBackboneIterator implements Iterator<PolymerBackbonePa
     private state: AtomicPolymerBackboneIteratorState = AtomicPolymerBackboneIteratorState.nextPolymer
     hasNext: boolean = false;
 
-    getElementIndex(residueIndex: ResidueIndex, atomType: 'trace' | 'direction') {
+    private getElementIndex(residueIndex: ResidueIndex, atomType: 'trace' | 'direction') {
         const index = getElementIndexForResidueTypeAtomId(this.unit.model, residueIndex, atomType)
         // // TODO handle case when it returns -1
         // return SortedArray.indexOf(this.unit.elements, index) as ElementIndex
@@ -239,6 +239,7 @@ interface PolymerTraceElement {
     center: StructureElement
     first: boolean, last: boolean
     secStrucType: SecondaryStructureType
+    secStrucChange: boolean
     t0: Vec3, t1: Vec3, t2: Vec3, t3: Vec3, t4: Vec3
     d12: Vec3, d23: Vec3
 }
@@ -248,6 +249,7 @@ function createPolymerTraceElement (unit: Unit): PolymerTraceElement {
         center: StructureElement.create(unit),
         first: false, last: false,
         secStrucType: SecondaryStructureType.create(SecondaryStructureType.Flag.NA),
+        secStrucChange: false,
         t0: Vec3.zero(), t1: Vec3.zero(), t2: Vec3.zero(), t3: Vec3.zero(), t4: Vec3.zero(),
         d12: Vec3.create(1, 0, 0), d23: Vec3.create(1, 0, 0),
     }
@@ -273,10 +275,10 @@ export class AtomicPolymerTraceIterator implements Iterator<PolymerTraceElement>
     private p5 = Vec3.zero();
     private p6 = Vec3.zero();
 
-    private v01 = Vec3.zero();
+    // private v01 = Vec3.zero();
     private v12 = Vec3.zero();
     private v23 = Vec3.zero();
-    private v34 = Vec3.zero();
+    // private v34 = Vec3.zero();
 
     hasNext: boolean = false;
 
@@ -286,18 +288,18 @@ export class AtomicPolymerTraceIterator implements Iterator<PolymerTraceElement>
         target[2] = this.unit.model.atomicConformation.z[index]
     }
 
-    updateResidueSegmentRange(polymerSegment: Segmentation.Segment<ResidueIndex>) {
+    private updateResidueSegmentRange(polymerSegment: Segmentation.Segment<ResidueIndex>) {
         const { index } = this.unit.model.atomicHierarchy.residueAtomSegments
         this.residueSegmentMin = index[this.unit.elements[polymerSegment.start]]
         this.residueSegmentMax = index[this.unit.elements[polymerSegment.end - 1]]
     }
 
-    getAtomIndex(residueIndex: number, atomType: 'trace' | 'direction') {
+    private getAtomIndex(residueIndex: number, atomType: 'trace' | 'direction') {
         const index = Math.min(Math.max(this.residueSegmentMin, residueIndex), this.residueSegmentMax)
         return getElementIndexForResidueTypeAtomId(this.unit.model, index as ResidueIndex, atomType)
     }
 
-    getElementIndex(residueIndex: number, atomType: 'trace' | 'direction') {
+    private getElementIndex(residueIndex: number, atomType: 'trace' | 'direction') {
         const index = this.getAtomIndex(residueIndex, atomType)
         // TODO handle case when it returns -1
         const elementIndex = SortedArray.indexOf(this.unit.elements, index) as ElementIndex
@@ -307,7 +309,7 @@ export class AtomicPolymerTraceIterator implements Iterator<PolymerTraceElement>
         return elementIndex === -1 ? 0 as ElementIndex : elementIndex
     }
 
-    setControlPoint(out: Vec3, p1: Vec3, p2: Vec3, p3: Vec3, residueIndex: number) {
+    private setControlPoint(out: Vec3, p1: Vec3, p2: Vec3, p3: Vec3, residueIndex: number) {
         const ss = this.unit.model.properties.secondaryStructure.type[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)
@@ -316,14 +318,14 @@ export class AtomicPolymerTraceIterator implements Iterator<PolymerTraceElement>
         }
     }
 
-    setDirectionVector(out: Vec3, p1: Vec3, p2: Vec3, p3: Vec3, residueIndex: number) {
-        const ss = this.unit.model.properties.secondaryStructure.type[residueIndex]
-        if (SecondaryStructureType.is(ss, SecondaryStructureType.Flag.Beta)) {
-            Vec3.scale(out, Vec3.add(out, p1, Vec3.add(out, p2, p3)), 1/3)
-        } else {
-            Vec3.copy(out, p2)
-        }
-    }
+    // private setDirectionVector(out: Vec3, p1: Vec3, p2: Vec3, p3: Vec3, residueIndex: number) {
+    //     const ss = this.unit.model.properties.secondaryStructure.type[residueIndex]
+    //     if (SecondaryStructureType.is(ss, SecondaryStructureType.Flag.Beta)) {
+    //         Vec3.scale(out, Vec3.add(out, p1, Vec3.add(out, p2, p3)), 1/3)
+    //     } else {
+    //         Vec3.copy(out, p2)
+    //     }
+    // }
 
     move() {
         const { residueIt, polymerIt, value } = this
@@ -352,10 +354,10 @@ export class AtomicPolymerTraceIterator implements Iterator<PolymerTraceElement>
             this.pos(this.p5, this.getAtomIndex(residueIndex + 2, 'trace'))
             this.pos(this.p6, this.getAtomIndex(residueIndex + 3, 'trace'))
 
-            this.pos(this.v01, this.getAtomIndex(residueIndex - 2, 'direction'))
+            // this.pos(this.v01, this.getAtomIndex(residueIndex - 2, 'direction'))
             this.pos(this.v12, this.getAtomIndex(residueIndex - 1, 'direction'))
             this.pos(this.v23, this.getAtomIndex(residueIndex, 'direction'))
-            this.pos(this.v34, this.getAtomIndex(residueIndex + 1, 'direction'))
+            // this.pos(this.v34, this.getAtomIndex(residueIndex + 1, 'direction'))
 
             this.value.secStrucType = this.unit.model.properties.secondaryStructure.type[residueIndex]
 
@@ -365,11 +367,14 @@ export class AtomicPolymerTraceIterator implements Iterator<PolymerTraceElement>
             this.setControlPoint(value.t3, this.p3, this.p4, this.p5, residueIndex + 1)
             this.setControlPoint(value.t4, this.p4, this.p5, this.p6, residueIndex + 2)
 
-            this.setDirectionVector(value.d12, this.v01, this.v12, this.v23, residueIndex)
-            this.setDirectionVector(value.d23, this.v12, this.v23, this.v34, residueIndex + 1)
+            // this.setDirectionVector(value.d12, this.v01, this.v12, this.v23, residueIndex)
+            // this.setDirectionVector(value.d23, this.v12, this.v23, this.v34, residueIndex + 1)
+            Vec3.copy(value.d12, this.v12)
+            Vec3.copy(value.d23, this.v23)
 
-            value.first = residueIndex === this.polymerSegment.start
-            value.last = residueIndex === this.polymerSegment.end - 1
+            value.first = residueIndex === this.residueSegmentMin
+            value.last = residueIndex === this.residueSegmentMax
+            value.secStrucChange = this.unit.model.properties.secondaryStructure.key[residueIndex] !== this.unit.model.properties.secondaryStructure.key[residueIndex + 1]
 
             if (!residueIt.hasNext) {
                 this.state = AtomicPolymerTraceIteratorState.nextPolymer

+ 7 - 65
src/mol-geo/shape/mesh-builder.ts

@@ -13,6 +13,8 @@ import Cylinder, { CylinderProps } from '../primitive/cylinder';
 import Icosahedron, { IcosahedronProps } from '../primitive/icosahedron';
 import { Mesh } from './mesh';
 import { getNormalMatrix } from '../util';
+import { addSheet } from '../primitive/sheet';
+import { addTube } from '../primitive/tube';
 
 type Primitive = {
     vertices: Float32Array
@@ -28,6 +30,7 @@ export interface MeshBuilder {
     addFixedCountDashedCylinder(start: Vec3, end: Vec3, lengthScale: number, segmentCount: number, props: CylinderProps): void
     addIcosahedron(center: Vec3, radius: number, detail: number): void
     addTube(controlPoints: Helpers.NumberArray, torsionVectors: Helpers.NumberArray, normalVectors: Helpers.NumberArray, linearSegments: number, radialSegments: number, width: number, height: number, waveFactor: number): void
+    addSheet(controlPoints: Helpers.NumberArray, normalVectors: Helpers.NumberArray, binormalVectors: Helpers.NumberArray, linearSegments: number, width: number, height: number, arrowWidth: number): void
     setId(id: number): void
     getMesh(): Mesh
 }
@@ -177,71 +180,10 @@ export namespace MeshBuilder {
                 add(tmpIcosahedronMat, vertices, normals, indices)
             },
             addTube: (controlPoints: Helpers.NumberArray, normalVectors: Helpers.NumberArray, binormalVectors: Helpers.NumberArray, linearSegments: number, radialSegments: number, width: number, height: number, waveFactor: number) => {
-                const normalVector = Vec3.zero()
-                const binormalVector = Vec3.zero()
-                const tempPos = Vec3.zero()
-                const a = Vec3.zero()
-                const b = Vec3.zero()
-                const u = Vec3.zero()
-                const v = Vec3.zero()
-
-                const vertexCount = vertices.elementCount
-                const di = 1 / linearSegments
-
-                for (let i = 0; i <= linearSegments; ++i) {
-                    const i3 = i * 3
-                    Vec3.fromArray(u, normalVectors, i3)
-                    Vec3.fromArray(v, binormalVectors, i3)
-
-                    const tt = di * i - 0.5;
-                    const ff = 1 + (waveFactor - 1) * (Math.cos(2 * Math.PI * tt) + 1);
-                    const w = ff * width, h = ff * height;
-
-                    for (let j = 0; j < radialSegments; ++j) {
-                        let t = 2 * Math.PI * j / radialSegments;
-
-                        Vec3.copy(a, u)
-                        Vec3.copy(b, v)
-                        Vec3.add(
-                            normalVector,
-                            Vec3.scale(a, a, w * Math.cos(t)),
-                            Vec3.scale(b, b, h * Math.sin(t))
-                        )
-
-                        Vec3.copy(a, u)
-                        Vec3.copy(b, v)
-                        Vec3.add(
-                            binormalVector,
-                            Vec3.scale(a, a, h * Math.cos(t)),
-                            Vec3.scale(b, b, w * Math.sin(t))
-                        )
-                        Vec3.normalize(normalVector, normalVector)
-
-                        Vec3.fromArray(tempPos, controlPoints, i3)
-                        Vec3.add(tempPos, tempPos, binormalVector)
-
-                        ChunkedArray.add3(vertices, tempPos[0], tempPos[1], tempPos[2]);
-                        ChunkedArray.add3(normals, normalVector[0], normalVector[1], normalVector[2]);
-                        ChunkedArray.add(ids, currentId);
-                    }
-                }
-
-                for (let i = 0; i < linearSegments; ++i) {
-                    for (let j = 0; j < radialSegments; ++j) {
-                        ChunkedArray.add3(
-                            indices,
-                            (vertexCount + i * radialSegments + (j + 1) % radialSegments),
-                            (vertexCount + (i + 1) * radialSegments + (j + 1) % radialSegments),
-                            (vertexCount + i * radialSegments + j)
-                        );
-                        ChunkedArray.add3(
-                            indices,
-                            (vertexCount + (i + 1) * radialSegments + (j + 1) % radialSegments),
-                            (vertexCount + (i + 1) * radialSegments + j),
-                            (vertexCount + i * radialSegments + j)
-                        );
-                    }
-                }
+                addTube(controlPoints, normalVectors, binormalVectors, linearSegments, radialSegments, width, height, waveFactor, vertices, normals, indices, ids, currentId)
+            },
+            addSheet: (controlPoints: Helpers.NumberArray, normalVectors: Helpers.NumberArray, binormalVectors: Helpers.NumberArray, linearSegments: number, width: number, height: number, arrowWidth: number) => {
+                addSheet(controlPoints, normalVectors, binormalVectors, linearSegments, width, height, arrowWidth, vertices, normals, indices, ids, currentId)
             },
             setId: (id: number) => {
                 if (currentId !== id) {

+ 2 - 2
src/mol-view/stage.ts

@@ -73,7 +73,7 @@ export class Stage {
 
         // this.loadPdbid('1jj2')
         // this.loadPdbid('4umt') // ligand has bond with order 3
-        this.loadPdbid('1crn') // small
+        // this.loadPdbid('1crn') // small
         // this.loadPdbid('1hrv') // viral assembly
         // this.loadPdbid('1rb8') // virus
         // this.loadPdbid('1blu') // metal coordination
@@ -82,7 +82,7 @@ export class Stage {
         // this.loadPdbid('3j3q') // ...
         // this.loadPdbid('3sn6') // discontinuous chains
         // this.loadMmcifUrl(`../../examples/1cbs_full.bcif`)
-        // this.loadMmcifUrl(`../../examples/1cbs_updated.cif`)
+        this.loadMmcifUrl(`../../examples/1cbs_updated.cif`)
         // this.loadMmcifUrl(`../../examples/1crn.cif`)
 
         // this.loadMmcifUrl(`../../../test/pdb-dev/PDBDEV_00000001.cif`) // ok