Browse Source

Merge branch 'master' of https://github.com/molstar/molstar-proto into plugin

David Sehnal 6 years ago
parent
commit
e5f7d3097a

+ 46 - 57
src/mol-geo/geometry/mesh/builder/sheet.ts

@@ -15,6 +15,8 @@ const tV = Vec3.zero()
 
 const horizontalVector = Vec3.zero()
 const verticalVector = Vec3.zero()
+const verticalRightVector = Vec3.zero()
+const verticalLeftVector = Vec3.zero()
 const normalOffset = Vec3.zero()
 const positionVector = Vec3.zero()
 const normalVector = Vec3.zero()
@@ -25,6 +27,41 @@ const p2 = Vec3.zero()
 const p3 = Vec3.zero()
 const p4 = Vec3.zero()
 
+function addCap(offset: number, builder: MeshBuilder, controlPoints: ArrayLike<number>, normalVectors: ArrayLike<number>, binormalVectors: ArrayLike<number>, width: number, leftHeight: number, rightHeight: number) {
+    const { vertices, normals, indices } = builder.state
+    const vertexCount = vertices.elementCount
+
+    Vec3.fromArray(verticalLeftVector, normalVectors, offset)
+    Vec3.scale(verticalLeftVector, verticalLeftVector, leftHeight)
+
+    Vec3.fromArray(verticalRightVector, normalVectors, offset)
+    Vec3.scale(verticalRightVector, verticalRightVector, rightHeight)
+
+    Vec3.fromArray(horizontalVector, binormalVectors, offset)
+    Vec3.scale(horizontalVector, horizontalVector, width)
+
+    Vec3.fromArray(positionVector, controlPoints, offset)
+
+    Vec3.add(p1, Vec3.add(p1, positionVector, horizontalVector), verticalRightVector)
+    Vec3.sub(p2, Vec3.add(p2, positionVector, horizontalVector), verticalLeftVector)
+    Vec3.sub(p3, Vec3.sub(p3, positionVector, horizontalVector), verticalLeftVector)
+    Vec3.add(p4, Vec3.sub(p4, positionVector, horizontalVector), verticalRightVector)
+
+    ChunkedArray.add3(vertices, p1[0], p1[1], p1[2])
+    ChunkedArray.add3(vertices, p2[0], p2[1], p2[2])
+    ChunkedArray.add3(vertices, p3[0], p3[1], p3[2])
+    ChunkedArray.add3(vertices, p4[0], p4[1], p4[2])
+
+    Vec3.cross(normalVector, horizontalVector, verticalLeftVector)
+
+    for (let i = 0; i < 4; ++i) {
+        ChunkedArray.add3(normals, normalVector[0], normalVector[1], normalVector[2])
+    }
+    ChunkedArray.add3(indices, vertexCount + 2, vertexCount + 1, vertexCount)
+    ChunkedArray.add3(indices, vertexCount, vertexCount + 3, vertexCount + 2)
+}
+
+/** set arrowHeight = 0 for no arrow */
 export function addSheet(builder: MeshBuilder, controlPoints: ArrayLike<number>, normalVectors: ArrayLike<number>, binormalVectors: ArrayLike<number>, linearSegments: number, width: number, height: number, arrowHeight: number, startCap: boolean, endCap: boolean) {
     const { currentGroup, vertices, normals, indices, groups } = builder.state
 
@@ -112,67 +149,19 @@ export function addSheet(builder: MeshBuilder, controlPoints: ArrayLike<number>,
     }
 
     if (startCap) {
-        const offset = 0
-        vertexCount = vertices.elementCount
-
-        Vec3.fromArray(verticalVector, normalVectors, offset)
-        Vec3.scale(verticalVector, verticalVector, arrowHeight === 0 ? height : arrowHeight);
-
-        Vec3.fromArray(horizontalVector, binormalVectors, offset)
-        Vec3.scale(horizontalVector, horizontalVector, width);
-
-        Vec3.fromArray(positionVector, controlPoints, offset)
-
-        Vec3.add(p1, Vec3.add(p1, positionVector, horizontalVector), verticalVector)
-        Vec3.sub(p2, Vec3.add(p2, positionVector, horizontalVector), verticalVector)
-        Vec3.sub(p3, Vec3.sub(p3, positionVector, horizontalVector), verticalVector)
-        Vec3.add(p4, Vec3.sub(p4, positionVector, horizontalVector), verticalVector)
-
-        ChunkedArray.add3(vertices, p1[0], p1[1], p1[2])
-        ChunkedArray.add3(vertices, p2[0], p2[1], p2[2])
-        ChunkedArray.add3(vertices, p3[0], p3[1], p3[2])
-        ChunkedArray.add3(vertices, p4[0], p4[1], p4[2])
-
-        Vec3.cross(normalVector, horizontalVector, verticalVector)
-
-        for (let i = 0; i < 4; ++i) {
-            ChunkedArray.add3(normals, normalVector[0], normalVector[1], normalVector[2])
-        }
-        ChunkedArray.add3(indices, vertexCount + 2, vertexCount + 1, vertexCount);
-        ChunkedArray.add3(indices, vertexCount, vertexCount + 3, vertexCount + 2);
+        const h = arrowHeight === 0 ? height : arrowHeight
+        addCap(0, builder, controlPoints, normalVectors, binormalVectors, width, h, h)
+    } else if (arrowHeight > 0) {
+        addCap(0, builder, controlPoints, normalVectors, binormalVectors, width, -arrowHeight, height)
+        addCap(0, builder, controlPoints, normalVectors, binormalVectors, width, arrowHeight, -height)
     }
 
     if (endCap && arrowHeight === 0) {
-        const offset = linearSegments * 3
-        vertexCount = vertices.elementCount
-
-        Vec3.fromArray(verticalVector, normalVectors, offset)
-        Vec3.scale(verticalVector, verticalVector, height);
-
-        Vec3.fromArray(horizontalVector, binormalVectors, offset)
-        Vec3.scale(horizontalVector, horizontalVector, width);
-
-        Vec3.fromArray(positionVector, controlPoints, offset)
-
-        Vec3.add(p1, Vec3.add(p1, positionVector, horizontalVector), verticalVector)
-        Vec3.sub(p2, Vec3.add(p2, positionVector, horizontalVector), verticalVector)
-        Vec3.sub(p3, Vec3.sub(p3, positionVector, horizontalVector), verticalVector)
-        Vec3.add(p4, Vec3.sub(p4, positionVector, horizontalVector), verticalVector)
-
-        ChunkedArray.add3(vertices, p1[0], p1[1], p1[2])
-        ChunkedArray.add3(vertices, p2[0], p2[1], p2[2])
-        ChunkedArray.add3(vertices, p3[0], p3[1], p3[2])
-        ChunkedArray.add3(vertices, p4[0], p4[1], p4[2])
-
-        Vec3.cross(normalVector, horizontalVector, verticalVector)
-
-        for (let i = 0; i < 4; ++i) {
-            ChunkedArray.add3(normals, normalVector[0], normalVector[1], normalVector[2])
-        }
-        ChunkedArray.add3(indices, vertexCount + 2, vertexCount + 1, vertexCount);
-        ChunkedArray.add3(indices, vertexCount, vertexCount + 3, vertexCount + 2);
+        addCap(linearSegments * 3, builder, controlPoints, normalVectors, binormalVectors, width, height, height)
     }
 
-    const addedVertexCount = (linearSegments + 1) * 8 + (startCap ? 4 : 0) + (endCap && arrowHeight === 0 ? 4 : 0)
+    const addedVertexCount = (linearSegments + 1) * 8 + 
+        (startCap ? 4 : (arrowHeight > 0 ? 8 : 0)) + 
+        (endCap && arrowHeight === 0 ? 4 : 0)
     for (let i = 0, il = addedVertexCount; i < il; ++i) ChunkedArray.add(groups, currentGroup)
 }

+ 9 - 1
src/mol-plugin/ui/controls/parameters.tsx

@@ -8,7 +8,7 @@
 import * as React from 'react'
 import { ParamDefinition as PD } from 'mol-util/param-definition';
 import { camelCaseToWords } from 'mol-util/string';
-import { ColorNames } from 'mol-util/color/tables';
+import { ColorNames, ColorNamesValueMap } from 'mol-util/color/tables';
 import { Color } from 'mol-util/color';
 import { Slider, Slider2 } from './slider';
 
@@ -172,6 +172,13 @@ function ColorOptions() {
     return _colors;
 }
 
+function ColorValueOption(color: Color) {
+    return !ColorNamesValueMap.has(color) ? <option key={Color.toHexString(color)} value={color} style={{ background: `${Color.toStyle(color)}` }} >
+        {Color.toHexString(color)}
+    </option> : null
+}
+
+
 export class ColorControl extends SimpleParam<PD.Color> {
     onChange = (e: React.ChangeEvent<HTMLSelectElement>) => {
         this.update(Color(parseInt(e.target.value)));
@@ -179,6 +186,7 @@ export class ColorControl extends SimpleParam<PD.Color> {
 
     renderControl() {
         return <select value={this.props.value} onChange={this.onChange} style={{ borderLeft: `16px solid ${Color.toStyle(this.props.value)}` }}>
+            {ColorValueOption(this.props.value)}
             {ColorOptions()}
         </select>;
     }

+ 1 - 1
src/mol-repr/structure/visual/polymer-direction-wedge.ts

@@ -62,7 +62,7 @@ async function createPolymerDirectionWedgeMesh(ctx: VisualContext, unit: Unit, s
 
         interpolateCurveSegment(state, v, tension, shift)
 
-        if ((isSheet && !v.secStrucChange) || !isSheet) {
+        if ((isSheet && !v.secStrucLast) || !isSheet) {
             const size = theme.size.size(v.center) * sizeFactor
             const depth = depthFactor * size
             const width = widthFactor * size

+ 4 - 4
src/mol-repr/structure/visual/polymer-trace-mesh.ts

@@ -52,7 +52,7 @@ async function createPolymerTraceMesh(ctx: VisualContext, unit: Unit, structure:
         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 || isSheet) ? 0.5 : 0.9
+        const tension = isNucleicType ? 0.5 : 0.9
         const shift = isNucleicType ? 0.3 : 0.5
 
         interpolateCurveSegment(state, v, tension, shift)
@@ -62,8 +62,8 @@ async function createPolymerTraceMesh(ctx: VisualContext, unit: Unit, structure:
 
         if (isSheet) {
             const height = width * aspectRatio
-            const arrowHeight = v.secStrucChange ? height * arrowFactor : 0
-            addSheet(builder, curvePoints, normalVectors, binormalVectors, linearSegments, width, height, arrowHeight, true, true)
+            const arrowHeight = v.secStrucLast ? height * arrowFactor : 0
+            addSheet(builder, curvePoints, normalVectors, binormalVectors, linearSegments, width, height, arrowHeight, v.secStrucFirst, v.secStrucLast)
         } else {
             let height: number
             if (isHelix) {
@@ -74,7 +74,7 @@ async function createPolymerTraceMesh(ctx: VisualContext, unit: Unit, structure:
             } else {
                 height = width
             }
-            addTube(builder, curvePoints, normalVectors, binormalVectors, linearSegments, radialSegments, width, height, 1, true, true)
+            addTube(builder, curvePoints, normalVectors, binormalVectors, linearSegments, radialSegments, width, height, 1, v.secStrucFirst, v.secStrucLast)
         }
 
         if (i % 10000 === 0 && ctx.runtime.shouldUpdate) {

+ 30 - 16
src/mol-repr/structure/visual/util/polymer/trace-iterator.ts

@@ -13,6 +13,7 @@ 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
@@ -30,20 +31,22 @@ export function PolymerTraceIterator(unit: Unit): Iterator<PolymerTraceElement>
 interface PolymerTraceElement {
     center: StructureElement
     first: boolean, last: boolean
+    secStrucFirst: boolean, secStrucLast: boolean
     secStrucType: SecondaryStructureType
-    secStrucChange: boolean
     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,
-        secStrucType: SecondaryStructureType.create(SecondaryStructureType.Flag.NA),
-        secStrucChange: 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),
@@ -57,10 +60,15 @@ export class AtomicPolymerTraceIterator implements Iterator<PolymerTraceElement>
     private polymerIt: SortedRanges.Iterator<ElementIndex, ResidueIndex>
     private residueIt: Segmentation.SegmentIterator<ResidueIndex>
     private polymerSegment: Segmentation.Segment<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();
@@ -78,13 +86,13 @@ export class AtomicPolymerTraceIterator implements Iterator<PolymerTraceElement>
     hasNext: boolean = false;
 
     private pos(target: Vec3, index: number) {
-        target[0] = this.unit.model.atomicConformation.x[index]
-        target[1] = this.unit.model.atomicConformation.y[index]
-        target[2] = this.unit.model.atomicConformation.z[index]
+        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.unit.model.atomicHierarchy.residueAtomSegments
+        const { index } = this.residueAtomSegments
         this.residueSegmentMin = index[this.unit.elements[polymerSegment.start]]
         this.residueSegmentMax = index[this.unit.elements[polymerSegment.end - 1]]
     }
@@ -111,8 +119,7 @@ export class AtomicPolymerTraceIterator implements Iterator<PolymerTraceElement>
     }
 
     private setControlPoint(out: Vec3, p1: Vec3, p2: Vec3, p3: Vec3, residueIndex: ResidueIndex) {
-        const ss = this.unit.model.properties.secondaryStructure.type[residueIndex]
-        if (SecondaryStructureType.is(ss, SecondaryStructureType.Flag.Beta)) {
+        if (SecondaryStructureType.is(this.currSecStrucType, 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)
@@ -129,6 +136,8 @@ export class AtomicPolymerTraceIterator implements Iterator<PolymerTraceElement>
                 this.updateResidueSegmentRange(this.polymerSegment)
                 if (residueIt.hasNext) {
                     this.state = AtomicPolymerTraceIteratorState.nextResidue
+                    this.currSecStrucType = SecStrucTypeNA
+                    this.nextSecStrucType = this.secondaryStructureType[this.residueSegmentMin]
                     break
                 }
             }
@@ -136,7 +145,17 @@ export class AtomicPolymerTraceIterator implements Iterator<PolymerTraceElement>
 
         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)
 
             this.pos(this.p0, this.getElementIndex(residueIndex - 3 as ResidueIndex, 'trace'))
             this.pos(this.p1, this.getElementIndex(residueIndex - 2 as ResidueIndex, 'trace'))
@@ -151,8 +170,6 @@ export class AtomicPolymerTraceIterator implements Iterator<PolymerTraceElement>
             this.pos(this.v23, this.getElementIndex(residueIndex, 'direction'))
             // this.pos(this.v34, this.getAtomIndex(residueIndex + 1 as ResidueIndex, 'direction'))
 
-            this.value.secStrucType = this.unit.model.properties.secondaryStructure.type[residueIndex]
-
             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)
@@ -162,11 +179,6 @@ export class AtomicPolymerTraceIterator implements Iterator<PolymerTraceElement>
             Vec3.copy(value.d12, this.v12)
             Vec3.copy(value.d23, this.v23)
 
-            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]
-            value.moleculeType = getAtomicMoleculeType(this.unit.model, residueIndex)
-
             if (!residueIt.hasNext) {
                 this.state = AtomicPolymerTraceIteratorState.nextPolymer
             }
@@ -178,7 +190,9 @@ export class AtomicPolymerTraceIterator implements Iterator<PolymerTraceElement>
     }
 
     constructor(private unit: Unit.Atomic) {
+        this.atomicConformation = unit.model.atomicConformation
         this.residueAtomSegments = unit.model.atomicHierarchy.residueAtomSegments
+        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)

+ 10 - 1
src/mol-util/color/tables.ts

@@ -259,4 +259,13 @@ export const ColorNames = ColorMap({
     whitesmoke: 0xf5f5f5,
     yellow: 0xffff00,
     yellowgreen: 0x9acd32
-})
+})
+export type ColorNames = typeof ColorNames
+export type ColorName = keyof ColorNames
+export const ColorNamesValueMap = (function(){
+    const map = new Map<Color, ColorName>()
+    Object.keys(ColorNames).forEach(name => {
+        map.set(ColorNames[name as ColorName], name as ColorName)
+    })
+    return map
+})()