Browse Source

wip, bond repr

Alexander Rose 6 years ago
parent
commit
acc7dcab14

+ 4 - 3
src/mol-geo/representation/index.ts

@@ -5,8 +5,9 @@
  */
 
 import { Task } from 'mol-task'
-import { RenderObject } from 'mol-gl/render-object';
-import { PickingId, PickingInfo } from '../util/picking';
+import { RenderObject } from 'mol-gl/render-object'
+import { PickingId } from '../util/picking';
+import { Loci } from 'mol-model/loci';
 
 export interface RepresentationProps {}
 
@@ -14,5 +15,5 @@ export interface Representation<D, P extends RepresentationProps = {}> {
     renderObjects: ReadonlyArray<RenderObject>
     create: (data: D, props?: P) => Task<void>
     update: (props: P) => Task<void>
-    getLabel: (pickingId: PickingId) => PickingInfo | null
+    getLoci: (pickingId: PickingId) => Loci | null
 }

+ 8 - 8
src/mol-geo/representation/structure/bond.ts

@@ -21,6 +21,7 @@ import { MeshBuilder } from '../../shape/mesh-builder';
 import { Vec3, Mat4 } from 'mol-math/linear-algebra';
 import { createUniformColor } from '../../util/color-data';
 import { defaults } from 'mol-util';
+import { SortedArray } from 'mol-data/int';
 
 function createBondMesh(unit: Unit, mesh?: Mesh) {
     return Task.create('Cylinder mesh', async ctx => {
@@ -31,7 +32,7 @@ function createBondMesh(unit: Unit, mesh?: Mesh) {
     
         if (!count) return Mesh.createEmpty(mesh)
 
-        // TODO calculate properly
+        // TODO calculate vertextCount properly
         const vertexCount = 32 * count
         const meshBuilder = MeshBuilder.create(vertexCount, vertexCount / 2, mesh)
 
@@ -91,7 +92,7 @@ export default function Bond(): UnitsRepresentation<BondProps> {
     let cylinders: MeshRenderObject
     let currentProps: typeof DefaultBondProps
     let mesh: Mesh
-    // let currentGroup: Unit.SymmetryGroup
+    let currentGroup: Unit.SymmetryGroup
     // let vertexMap: VertexMap
 
     return {
@@ -101,7 +102,7 @@ export default function Bond(): UnitsRepresentation<BondProps> {
 
             return Task.create('Bond.create', async ctx => {
                 renderObjects.length = 0 // clear
-                // currentGroup = group
+                currentGroup = group
 
                 mesh = await createBondMesh(group.units[0]).runAsChild(ctx, 'Computing bond mesh')
                 // console.log(mesh)
@@ -165,13 +166,12 @@ export default function Bond(): UnitsRepresentation<BondProps> {
                 return true
             })
         },
-        getLocation(pickingId: PickingId) {
+        getLoci(pickingId: PickingId) {
             // const { objectId, instanceId, elementId } = pickingId
             // if (cylinders.id === objectId) {
-            //     const l = Element.Location()
-            //     l.unit = currentGroup.units[instanceId]
-            //     l.element = currentGroup.elements[elementId]
-            //     return l
+            //     const unit = currentGroup.units[instanceId]
+            //     const elements = SortedArray.ofSingleton(currentGroup.elements[elementId])
+            //     return Element.Loci([{ unit, elements }])
             // }
             return null
         }

+ 8 - 42
src/mol-geo/representation/structure/index.ts

@@ -5,26 +5,26 @@
  * @author David Sehnal <david.sehnal@gmail.com>
  */
 
-import { Structure, StructureSymmetry, Unit, Element, Queries } from 'mol-model/structure';
+import { Structure, StructureSymmetry, Unit } from 'mol-model/structure';
 import { Task } from 'mol-task'
 import { RenderObject } from 'mol-gl/render-object';
 import { Representation, RepresentationProps } from '..';
 import { ColorTheme } from '../../theme';
-import { PickingId, PickingInfo } from '../../util/picking';
+import { PickingId } from '../../util/picking';
+import { Loci } from 'mol-model/loci';
 
 export interface UnitsRepresentation<P> {
     renderObjects: ReadonlyArray<RenderObject>
     create: (group: Unit.SymmetryGroup, props: P) => Task<void>
     update: (props: P) => Task<boolean>
-    getLocation: (pickingId: PickingId) => Element.Location | null
+    getLoci: (pickingId: PickingId) => Loci | null
 }
 
 export interface StructureRepresentation<P extends RepresentationProps = {}> extends Representation<Structure, P> {
     renderObjects: ReadonlyArray<RenderObject>
     create: (structure: Structure, props?: P) => Task<void>
     update: (props: P) => Task<void>
-    getLocation: (pickingId: PickingId) => Element.Location | null
-    getLabel: (pickingId: PickingId) => PickingInfo | null
+    getLoci: (pickingId: PickingId) => Loci | null
 }
 
 interface GroupRepresentation<T> {
@@ -32,36 +32,6 @@ interface GroupRepresentation<T> {
     group: Unit.SymmetryGroup
 }
 
-function label(loc: Element.Location) {
-    const model = loc.unit.model.label
-    const instance = loc.unit.conformation.operator.name
-    let element = ''
-
-    if (Unit.isAtomic(loc.unit)) {
-        const asym_id = Queries.props.chain.auth_asym_id(loc)
-        const seq_id = Queries.props.residue.auth_seq_id(loc)
-        const comp_id = Queries.props.residue.auth_comp_id(loc)
-        const atom_id = Queries.props.atom.auth_atom_id(loc)
-        element = `[${comp_id}]${seq_id}:${asym_id}.${atom_id}`
-    } else if (Unit.isCoarse(loc.unit)) {
-        const asym_id = Queries.props.coarse.asym_id(loc)
-        const seq_id_begin = Queries.props.coarse.seq_id_begin(loc)
-        const seq_id_end = Queries.props.coarse.seq_id_end(loc)
-        if (seq_id_begin === seq_id_end) {
-            const entityKey = Queries.props.coarse.entityKey(loc)
-            const seq = loc.unit.model.sequence.byEntityKey[entityKey]
-            const comp_id = seq.compId.value(seq_id_begin)
-            element = `[${comp_id}]${seq_id_begin}:${asym_id}`
-        } else {
-            element = `${seq_id_begin}-${seq_id_end}:${asym_id}`
-        }
-    } else {
-        element = 'unknown'
-    }
-
-    return { label: `${model} ${instance} ${element}` }
-}
-
 export const DefaultStructureProps = {
     colorTheme: { name: 'instance-index' } as ColorTheme,
     alpha: 1,
@@ -77,9 +47,9 @@ export function StructureRepresentation<P extends StructureProps>(reprCtor: () =
     const groupReprs: GroupRepresentation<P>[] = []
     // let currentProps: typeof DefaultStructureProps
 
-    function getLocation(pickingId: PickingId) {
+    function getLoci(pickingId: PickingId) {
         for (let i = 0, il = groupReprs.length; i < il; ++i) {
-            const loc = groupReprs[i].repr.getLocation(pickingId)
+            const loc = groupReprs[i].repr.getLoci(pickingId)
             if (loc) return loc
         }
         return null
@@ -121,10 +91,6 @@ export function StructureRepresentation<P extends StructureProps>(reprCtor: () =
                 }
             })
         },
-        getLocation,
-        getLabel(pickingId: PickingId) {
-            const loc = getLocation(pickingId)
-            return loc ? label(loc) : null
-        }
+        getLoci
     }
 }

+ 4 - 5
src/mol-geo/representation/structure/point.ts

@@ -155,13 +155,12 @@ export default function Point(): UnitsRepresentation<PointProps> {
                 return false
             })
         },
-        getLocation(pickingId: PickingId) {
+        getLoci(pickingId: PickingId) {
             const { objectId, instanceId, elementId } = pickingId
             if (points.id === objectId) {
-                const l = Element.Location()
-                l.unit = currentGroup.units[instanceId]
-                l.element = currentGroup.elements[elementId]
-                return l
+                const unit = currentGroup.units[instanceId]
+                const elements = SortedArray.ofSingleton(currentGroup.elements[elementId])
+                return Element.Loci([{ unit, elements }])
             }
             return null
         }

+ 5 - 5
src/mol-geo/representation/structure/spacefill.ts

@@ -19,6 +19,7 @@ import { RenderableState, MeshValues } from 'mol-gl/renderable';
 import { getMeshData } from '../../util/mesh-data';
 import { Mesh } from '../../shape/mesh';
 import { PickingId } from '../../util/picking';
+import { SortedArray } from 'mol-data/int';
 
 function createSpacefillMesh(unit: Unit, detail: number, mesh?: Mesh) {
     let radius: Element.Property<number>
@@ -150,13 +151,12 @@ export default function Spacefill(): UnitsRepresentation<SpacefillProps> {
                 return true
             })
         },
-        getLocation(pickingId: PickingId) {
+        getLoci(pickingId: PickingId) {
             const { objectId, instanceId, elementId } = pickingId
             if (spheres.id === objectId) {
-                const l = Element.Location()
-                l.unit = currentGroup.units[instanceId]
-                l.element = currentGroup.elements[elementId]
-                return l
+                const unit = currentGroup.units[instanceId]
+                const elements = SortedArray.ofSingleton(currentGroup.elements[elementId])
+                return Element.Loci([{ unit, elements }])
             }
             return null
         }

+ 4 - 2
src/mol-geo/representation/volume/index.ts

@@ -9,6 +9,7 @@ import { RenderObject } from 'mol-gl/render-object';
 import { RepresentationProps, Representation } from '..';
 import { VolumeData } from 'mol-model/volume';
 import { PickingId, PickingInfo } from '../../util/picking';
+import { Loci } from 'mol-model/loci';
 
 export interface VolumeElementRepresentation<P> {
     renderObjects: ReadonlyArray<RenderObject>
@@ -21,7 +22,7 @@ export interface VolumeRepresentation<P extends RepresentationProps = {}> extend
     renderObjects: ReadonlyArray<RenderObject>
     create: (volumeData: VolumeData, props?: P) => Task<void>
     update: (props: P) => Task<void>
-    getLabel: (pickingId: PickingId) => PickingInfo | null
+    getLoci: (pickingId: PickingId) => Loci | null
 }
 
 export function VolumeRepresentation<P>(reprCtor: () => VolumeElementRepresentation<P>): VolumeRepresentation<P> {
@@ -39,7 +40,8 @@ export function VolumeRepresentation<P>(reprCtor: () => VolumeElementRepresentat
         update(props: P) {
             return Task.create('VolumeRepresentation.update', async ctx => {})
         },
-        getLabel(pickingId: PickingId) {
+        getLoci(pickingId: PickingId) {
+            // TODO
             return null
         }
     }

+ 10 - 0
src/mol-model/loci.ts

@@ -0,0 +1,10 @@
+/**
+ * Copyright (c) 2018 mol* contributors, licensed under MIT, See LICENSE file for more info.
+ *
+ * @author Alexander Rose <alexander.rose@weirdbyte.de>
+ */
+
+import { Element } from './structure'
+import { Bond } from './structure/structure/unit/bonds'
+
+export type Loci =  Element.Loci | Bond.Loci

+ 55 - 0
src/mol-view/label.ts

@@ -0,0 +1,55 @@
+/**
+ * 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 { Unit, Element, Queries } from 'mol-model/structure';
+import { Bond } from 'mol-model/structure/structure/unit/bonds';
+import { Loci } from 'mol-model/loci';
+
+export function labelFirst(loci: Loci) {
+    if(Element.isLoci(loci)) {
+        const e = loci.elements[0]
+        if (e && e.elements[0] !== undefined) {
+            return elementLabel(Element.Location(e.unit, e.elements[0]))
+        }
+    } else if (Bond.isLoci(loci)) {
+        const bond = loci.bonds[0]
+        if (bond) {
+            return `${elementLabel(bond.a)} - ${elementLabel(bond.b)}`
+        }
+    }
+    return ''
+}
+
+export function elementLabel(loc: Element.Location) {
+    const model = loc.unit.model.label
+    const instance = loc.unit.conformation.operator.name
+    let element = ''
+
+    if (Unit.isAtomic(loc.unit)) {
+        const asym_id = Queries.props.chain.auth_asym_id(loc)
+        const seq_id = Queries.props.residue.auth_seq_id(loc)
+        const comp_id = Queries.props.residue.auth_comp_id(loc)
+        const atom_id = Queries.props.atom.auth_atom_id(loc)
+        element = `[${comp_id}]${seq_id}:${asym_id}.${atom_id}`
+    } else if (Unit.isCoarse(loc.unit)) {
+        const asym_id = Queries.props.coarse.asym_id(loc)
+        const seq_id_begin = Queries.props.coarse.seq_id_begin(loc)
+        const seq_id_end = Queries.props.coarse.seq_id_end(loc)
+        if (seq_id_begin === seq_id_end) {
+            const entityKey = Queries.props.coarse.entityKey(loc)
+            const seq = loc.unit.model.sequence.byEntityKey[entityKey]
+            const comp_id = seq.compId.value(seq_id_begin)
+            element = `[${comp_id}]${seq_id_begin}:${asym_id}`
+        } else {
+            element = `${seq_id_begin}-${seq_id_end}:${asym_id}`
+        }
+    } else {
+        element = 'unknown'
+    }
+
+    return `${model} ${instance} ${element}`
+}

+ 3 - 2
src/mol-view/viewer.ts

@@ -22,6 +22,7 @@ import { createRenderTarget } from 'mol-gl/webgl/render-target';
 import Scene from 'mol-gl/scene';
 import { RenderVariant } from 'mol-gl/webgl/render-item';
 import { PickingId, decodeIdRGBA } from 'mol-geo/util/picking';
+import { labelFirst } from './label';
 
 interface Viewer {
     center: (p: Vec3) => void
@@ -80,8 +81,8 @@ namespace Viewer {
             const p = identify(x, y)
             let label = ''
             reprMap.forEach((roSet, repr) => {
-                const info = repr.getLabel(p)
-                if (info) label = info.label
+                const loci = repr.getLoci(p)
+                if (loci) label = labelFirst(loci)
                 repr.update({ hoverSelection: p }).run().then(() => {
                     scene.update()
                     requestDraw()