Browse Source

Merge branch 'master' into graphics

Alexander Rose 6 years ago
parent
commit
3532b0d7ea

+ 16 - 1
src/mol-plugin/state/actions/data-format.ts

@@ -13,6 +13,7 @@ import { ParamDefinition as PD } from 'mol-util/param-definition';
 import { Ccp4Provider, Dsn6Provider, DscifProvider } from './volume';
 import { StateTransforms } from '../transforms';
 import { MmcifProvider, PdbProvider, GroProvider } from './structure';
+import msgpackDecode from 'mol-io/common/msgpack/decode'
 
 export class DataFormatRegistry<D extends PluginStateObject.Data.Binary | PluginStateObject.Data.String> {
     private _list: { name: string, provider: DataFormatProvider<D> }[] = []
@@ -139,4 +140,18 @@ export const OpenFile = StateAction.build({
     const b = state.build().to(data.ref);
     // need to await the 2nd update the so that the enclosing Task finishes after the update is done.
     await provider.getDefaultBuilder(ctx, b, state).runInContext(taskCtx)
-}));
+}));
+
+//
+
+type cifVariants = 'dscif' | -1
+export function guessCifVariant(info: FileInfo, data: Uint8Array | string): cifVariants {
+    if (info.ext === 'bcif') {
+        try {
+            if (msgpackDecode(data as Uint8Array).encoder.startsWith('VolumeServer')) return 'dscif'
+        } catch { }
+    } else if (info.ext === 'cif') {
+        if ((data as string).startsWith('data_SERVER\n#\n_density_server_result')) return 'dscif'
+    }
+    return -1
+}

+ 5 - 2
src/mol-plugin/state/actions/structure.ts

@@ -13,7 +13,7 @@ import { StateTransforms } from '../transforms';
 import { Download } from '../transforms/data';
 import { StructureRepresentation3DHelpers } from '../transforms/representation';
 import { CustomModelProperties, StructureSelection } from '../transforms/model';
-import { DataFormatProvider } from './data-format';
+import { DataFormatProvider, guessCifVariant } from './data-format';
 import { FileInfo } from 'mol-util/file-info';
 import { Task } from 'mol-task';
 import { StructureElement } from 'mol-model/structure';
@@ -24,7 +24,10 @@ export const MmcifProvider: DataFormatProvider<any> = {
     stringExtensions: ['cif', 'mmcif', 'mcif'],
     binaryExtensions: ['bcif'],
     isApplicable: (info: FileInfo, data: Uint8Array | string) => {
-        return info.ext === 'cif' || info.ext === 'mmcif' || info.ext === 'mcif' || info.ext === 'bcif'
+        if (info.ext === 'mmcif' || info.ext === 'mcif') return true
+        // assume cif/bcif files that are not DensityServer CIF are mmCIF
+        if (info.ext === 'cif' || info.ext === 'bcif') return guessCifVariant(info, data) !== 'dscif'
+        return false
     },
     getDefaultBuilder: (ctx: PluginContext, data: StateBuilder.To<PluginStateObject.Data.Binary | PluginStateObject.Data.String>, state: State) => {
         return Task.create('mmCIF default builder', async taskCtx => {

+ 4 - 4
src/mol-plugin/state/actions/volume.ts

@@ -16,7 +16,7 @@ import { PluginStateObject } from '../objects';
 import { StateTransforms } from '../transforms';
 import { Download } from '../transforms/data';
 import { VolumeRepresentation3DHelpers } from '../transforms/representation';
-import { DataFormatProvider } from './data-format';
+import { DataFormatProvider, guessCifVariant } from './data-format';
 
 export const Ccp4Provider: DataFormatProvider<any> = {
     label: 'CCP4/MRC/BRIX',
@@ -59,10 +59,10 @@ export const DscifProvider: DataFormatProvider<any> = {
     description: 'DensityServer CIF',
     stringExtensions: ['cif'],
     binaryExtensions: ['bcif'],
-    isApplicable: (info: FileInfo, data: Uint8Array) => {
-        return info.ext === 'cif' || info.ext === 'bcif'
+    isApplicable: (info: FileInfo, data: Uint8Array | string) => {
+        return guessCifVariant(info, data) === 'dscif' ? true : false
     },
-    getDefaultBuilder: (ctx: PluginContext, data: StateBuilder.To<PluginStateObject.Data.Binary>, state: State) => {
+    getDefaultBuilder: (ctx: PluginContext, data: StateBuilder.To<PluginStateObject.Data.Binary | PluginStateObject.Data.String>, state: State) => {
         return Task.create('DensityServer CIF default builder', async taskCtx => {
             const cifBuilder = data.apply(StateTransforms.Data.ParseCif)
             const cifStateObject = await state.updateTree(cifBuilder).runInContext(taskCtx)

+ 1 - 1
src/mol-repr/structure/visual/util/common.ts

@@ -11,7 +11,7 @@ import { OrderedSet, SortedArray } from 'mol-data/int';
 import { EmptyLoci, Loci } from 'mol-model/loci';
 
 /** Return a Loci for the elements of a whole residue the elementIndex belongs to. */
-export function getResidueLoci(structure: Structure, unit: Unit, elementIndex: ElementIndex): Loci {
+export function getResidueLoci(structure: Structure, unit: Unit.Atomic, elementIndex: ElementIndex): Loci {
     const { elements, model } = unit
     if (OrderedSet.indexOf(elements, elementIndex) !== -1) {
         const { index, offsets } = model.atomicHierarchy.residueAtomSegments

+ 40 - 14
src/mol-repr/structure/visual/util/polymer.ts

@@ -72,12 +72,25 @@ export function getPolymerElementLoci(pickingId: PickingId, structureGroup: Stru
     if (id === objectId) {
         const { structure, group } = structureGroup
         const unit = group.units[instanceId]
-        return getResidueLoci(structure, unit, unit.polymerElements[groupId])
+        if (Unit.isAtomic(unit)) {
+            return getResidueLoci(structure, unit, unit.polymerElements[groupId])
+        } else {
+            const { elements } = unit
+            const elementIndex = unit.polymerElements[groupId]
+            const unitIndex = OrderedSet.indexOf(elements, elementIndex) as StructureElement.UnitIndex | -1
+            if (unitIndex !== -1) {
+                const indices = OrderedSet.ofSingleton(unitIndex)
+                return StructureElement.Loci(structure, [{ unit, indices }])
+            }
+        }
     }
     return EmptyLoci
 }
 
-/** Mark a polymer element (e.g. part of a cartoon trace) when all its residue's elements are in a loci. */
+/**
+ * Mark a polymer element (e.g. part of a cartoon trace)
+ * - for atomic units mark only when all its residue's elements are in a loci
+ */
 export function eachPolymerElement(loci: Loci, structureGroup: StructureGroup, apply: (interval: Interval) => boolean) {
     let changed = false
     if (!StructureElement.isLoci(loci)) return false
@@ -90,19 +103,32 @@ export function eachPolymerElement(loci: Loci, structureGroup: StructureGroup, a
     for (const e of loci.elements) {
         const unitIdx = group.unitIndexMap.get(e.unit.id)
         if (unitIdx !== undefined) {
-            // TODO optimized implementation for intervals
-            OrderedSet.forEach(e.indices, v => {
-                const rI = index[elements[v]]
-                const unitIndexMin = OrderedSet.findPredecessorIndex(elements, offsets[rI])
-                const unitIndexMax = OrderedSet.findPredecessorIndex(elements, offsets[rI + 1] - 1)
-                const unitIndexInterval = Interval.ofRange(unitIndexMin, unitIndexMax)
-                if (!OrderedSet.isSubset(e.indices, unitIndexInterval)) return
-                const eI = traceElementIndex[rI]
-                const idx = OrderedSet.indexOf(e.unit.polymerElements, eI)
-                if (idx !== -1) {
-                    if (apply(Interval.ofSingleton(unitIdx * groupCount + idx))) changed = true
+            if (Unit.isAtomic(e.unit)) {
+                // TODO optimized implementation for intervals
+                OrderedSet.forEach(e.indices, v => {
+                    const rI = index[elements[v]]
+                    const unitIndexMin = OrderedSet.findPredecessorIndex(elements, offsets[rI])
+                    const unitIndexMax = OrderedSet.findPredecessorIndex(elements, offsets[rI + 1] - 1)
+                    const unitIndexInterval = Interval.ofRange(unitIndexMin, unitIndexMax)
+                    if (!OrderedSet.isSubset(e.indices, unitIndexInterval)) return
+                    const eI = traceElementIndex[rI]
+                    const idx = OrderedSet.indexOf(e.unit.polymerElements, eI)
+                    if (idx !== -1) {
+                        if (apply(Interval.ofSingleton(unitIdx * groupCount + idx))) changed = true
+                    }
+                })
+            } else {
+                if (Interval.is(e.indices)) {
+                    const start = unitIdx * groupCount + Interval.start(e.indices);
+                    const end = unitIdx * groupCount + Interval.end(e.indices);
+                    if (apply(Interval.ofBounds(start, end))) changed = true
+                } else {
+                    for (let i = 0, _i = e.indices.length; i < _i; i++) {
+                        const idx = unitIdx * groupCount + e.indices[i];
+                        if (apply(Interval.ofSingleton(idx))) changed = true
+                    }
                 }
-            })
+            }
         }
     }
     return changed