Browse Source

InterUnitLink improvements

Alexander Rose 5 years ago
parent
commit
4fe70de2ff
1 changed files with 57 additions and 19 deletions
  1. 57 19
      src/mol-repr/structure/visual/inter-unit-link-cylinder.ts

+ 57 - 19
src/mol-repr/structure/visual/inter-unit-link-cylinder.ts

@@ -1,12 +1,12 @@
 /**
- * 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>
  */
 
 import { ParamDefinition as PD } from '../../../mol-util/param-definition';
 import { VisualContext } from '../../visual';
-import { Structure, StructureElement, Link } from '../../../mol-model/structure';
+import { Structure, StructureElement, Link, Unit } from '../../../mol-model/structure';
 import { Theme } from '../../../mol-theme/theme';
 import { Mesh } from '../../../mol-geo/geometry/mesh/mesh';
 import { Vec3 } from '../../../mol-math/linear-algebra';
@@ -19,18 +19,44 @@ import { EmptyLoci, Loci } from '../../../mol-model/loci';
 import { Interval, OrderedSet } from '../../../mol-data/int';
 import { isHydrogen } from './util/common';
 
+const tmpRefPosLinkIt = new Link.ElementLinkIterator()
+function setRefPosition(pos: Vec3, structure: Structure, unit: Unit.Atomic, index: StructureElement.UnitIndex) {
+    tmpRefPosLinkIt.setElement(structure, unit, index)
+    while (tmpRefPosLinkIt.hasNext) {
+        const bA = tmpRefPosLinkIt.move()
+        bA.otherUnit.conformation.position(bA.otherUnit.elements[bA.otherIndex], pos)
+        return pos
+    }
+    return null
+}
+
+const tmpRef = Vec3()
+const tmpLoc = StructureElement.Location.create()
+
 function createInterUnitLinkCylinderMesh(ctx: VisualContext, structure: Structure, theme: Theme, props: PD.Values<InterUnitLinkParams>, mesh?: Mesh) {
-    const links = structure.links
+    const links = structure.interUnitBonds
     const { bondCount, bonds } = links
     const { sizeFactor, sizeAspectRatio, ignoreHydrogens } = props
 
     if (!bondCount) return Mesh.createEmpty(mesh)
 
-    const location = StructureElement.Location.create()
-
     const builderProps = {
         linkCount: bondCount,
-        referencePosition: (edgeIndex: number) => null, // TODO
+        referencePosition: (edgeIndex: number) => {
+            const b = bonds[edgeIndex]
+            let unitA: Unit, unitB: Unit
+            let indexA: StructureElement.UnitIndex, indexB: StructureElement.UnitIndex
+            if (b.unitA.id < b.unitB.id) {
+                unitA = b.unitA, unitB = b.unitB
+                indexA = b.indexA, indexB = b.indexB
+            } else if (b.unitA.id > b.unitB.id) {
+                unitA = b.unitB, unitB = b.unitA
+                indexA = b.indexB, indexB = b.indexA
+            } else {
+                throw new Error('same units in createInterUnitLinkCylinderMesh')
+            }
+            return setRefPosition(tmpRef, structure, unitA, indexA) || setRefPosition(tmpRef, structure, unitB, indexB)
+        },
         position: (posA: Vec3, posB: Vec3, edgeIndex: number) => {
             const b = bonds[edgeIndex]
             const uA = b.unitA, uB = b.unitB
@@ -41,12 +67,12 @@ function createInterUnitLinkCylinderMesh(ctx: VisualContext, structure: Structur
         flags: (edgeIndex: number) => BitFlags.create(bonds[edgeIndex].flag),
         radius: (edgeIndex: number) => {
             const b = bonds[edgeIndex]
-            location.unit = b.unitA
-            location.element = b.unitA.elements[b.indexA]
-            const sizeA = theme.size.size(location)
-            location.unit = b.unitB
-            location.element = b.unitB.elements[b.indexB]
-            const sizeB = theme.size.size(location)
+            tmpLoc.unit = b.unitA
+            tmpLoc.element = b.unitA.elements[b.indexA]
+            const sizeA = theme.size.size(tmpLoc)
+            tmpLoc.unit = b.unitB
+            tmpLoc.element = b.unitB.elements[b.indexB]
+            const sizeB = theme.size.size(tmpLoc)
             return Math.min(sizeA, sizeB) * sizeFactor * sizeAspectRatio
         },
         ignore: ignoreHydrogens ? (edgeIndex: number) => {
@@ -92,7 +118,7 @@ export function InterUnitLinkVisual(materialId: number): ComplexVisual<InterUnit
 function getLinkLoci(pickingId: PickingId, structure: Structure, id: number) {
     const { objectId, groupId } = pickingId
     if (id === objectId) {
-        const bond = structure.links.bonds[groupId]
+        const bond = structure.interUnitBonds.bonds[groupId]
         return Link.Loci(structure, [
             Link.Location(
                 bond.unitA, bond.indexA as StructureElement.UnitIndex,
@@ -112,19 +138,31 @@ function eachLink(loci: Loci, structure: Structure, apply: (interval: Interval)
     if (Link.isLoci(loci)) {
         if (!Structure.areEquivalent(loci.structure, structure)) return false
         for (const b of loci.links) {
-            const idx = structure.links.getBondIndex(b.aIndex, b.aUnit, b.bIndex, b.bUnit)
+            const idx = structure.interUnitBonds.getBondIndex(b.aIndex, b.aUnit, b.bIndex, b.bUnit)
             if (idx !== -1) {
                 if (apply(Interval.ofSingleton(idx))) changed = true
             }
         }
     } else if (StructureElement.Loci.is(loci)) {
         if (!Structure.areEquivalent(loci.structure, structure)) return false
-        // TODO mark link only when both of the link elements are in a StructureElement.Loci
+        if (loci.elements.length === 1) return false // only a single unit
+
+        const map = new Map<number, OrderedSet<StructureElement.UnitIndex>>()
+        for (const e of loci.elements) map.set(e.unit.id, e.indices)
+
         for (const e of loci.elements) {
-            OrderedSet.forEach(e.indices, v => {
-                const indices = structure.links.getBondIndices(v, e.unit)
-                for (let i = 0, il = indices.length; i < il; ++i) {
-                    if (apply(Interval.ofSingleton(indices[i]))) changed = true
+            structure.interUnitBonds.getLinkedUnits(e.unit).forEach(b => {
+                const otherLociIndices = map.get(b.unitB.id)
+                if (otherLociIndices) {
+                    OrderedSet.forEach(e.indices, v => {
+                        if (!b.linkedElementIndices.includes(v)) return
+                        b.getBonds(v).forEach(bi => {
+                            if (OrderedSet.has(otherLociIndices, bi.indexB)) {
+                                const idx = structure.interUnitBonds.getBondIndex(v, e.unit, bi.indexB, b.unitB)
+                                if (apply(Interval.ofSingleton(idx))) changed = true
+                            }
+                        })
+                    })
                 }
             })
         }