Ver Fonte

loci helper methods, isEmpty

Alexander Rose há 5 anos atrás
pai
commit
90a3d302f3

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

@@ -40,6 +40,9 @@ export function isDataLoci(x: any): x is DataLoci {
 export function areDataLociEqual(a: DataLoci, b: DataLoci) {
     return a.data === b.data && a.tag === b.tag && OrderedSet.areEqual(a.indices, b.indices)
 }
+export function isDataLociEmpty(loci: DataLoci) {
+    return OrderedSet.size(loci.indices) === 0 ? true : false
+}
 export function createDataLoci(data: any, tag: string, indices: OrderedSet<number>): DataLoci {
     return { kind: 'data-loci', data, tag, indices }
 }
@@ -73,6 +76,29 @@ namespace Loci {
         return false
     }
 
+    export function isEmpty(loci: Loci) {
+        if (isEveryLoci(loci)) return false
+        if (isEmptyLoci(loci)) return true
+        if (isDataLoci(loci)) return isDataLociEmpty(loci)
+        if (Structure.isLoci(loci)) return Structure.isLociEmpty(loci)
+        if (StructureElement.Loci.is(loci)) StructureElement.Loci.isEmpty(loci)
+        if (Link.isLoci(loci)) Link.isLociEmpty(loci)
+        if (Shape.isLoci(loci)) return Shape.isLociEmpty(loci)
+        if (ShapeGroup.isLoci(loci)) return ShapeGroup.isLociEmpty(loci)
+        return false
+    }
+
+    export function remap<T>(loci: Loci, data: T) {
+        if (data instanceof Structure) {
+            if (StructureElement.Loci.is(loci)) {
+                loci = StructureElement.Loci.remap(loci, data)
+            } else if (Link.isLoci(loci)) {
+                loci = Link.remapLoci(loci, data)
+            }
+        }
+        return loci
+    }
+
     const sphereHelper = new CentroidHelper(), tempPos = Vec3.zero();
 
     export function getBoundingSphere(loci: Loci, boundingSphere?: Sphere3D): Sphere3D | undefined {

+ 13 - 0
src/mol-model/shape/shape.ts

@@ -50,6 +50,7 @@ export namespace Shape {
     export function Loci(shape: Shape): Loci { return { kind: 'shape-loci', shape } }
     export function isLoci(x: any): x is Loci { return !!x && x.kind === 'shape-loci' }
     export function areLociEqual(a: Loci, b: Loci) { return a.shape === b.shape }
+    export function isLociEmpty(loci: Loci) { return loci.shape.groupCount === 0 ? true : false }
 }
 
 export namespace ShapeGroup {
@@ -96,4 +97,16 @@ export namespace ShapeGroup {
         }
         return true
     }
+
+    export function isLociEmpty(loci: Loci) {
+        return size(loci) === 0 ? true : false
+    }
+
+    export function size(loci: Loci) {
+        let size = 0
+        for (const group of loci.groups) {
+            size += OrderedSet.size(group.ids)
+        }
+        return size
+    }
 }

+ 8 - 4
src/mol-model/structure/structure/element/loci.ts

@@ -53,6 +53,10 @@ export namespace Loci {
         return true
     }
 
+    export function isEmpty(loci: Loci) {
+        return size(loci) === 0 ? true : false
+    }
+
     export function size(loci: Loci) {
         let s = 0;
         for (const u of loci.elements) s += OrderedSet.size(u.indices);
@@ -101,7 +105,7 @@ export namespace Loci {
                     indices = SortedArray.ofSortedArray(_indices)
                 }
 
-                elements.push({ unit, indices })
+                if (OrderedSet.size(indices) > 0) elements.push({ unit, indices })
             }
         });
 
@@ -111,7 +115,7 @@ export namespace Loci {
     /** Create union of `xs` and `ys` */
     export function union(xs: Loci, ys: Loci): Loci {
         if (xs.elements.length > ys.elements.length) return union(ys, xs);
-        if (xs.elements.length === 0) return ys;
+        if (Loci.isEmpty(xs)) return ys;
 
         const map = new Map<number, OrderedSet<UnitIndex>>();
 
@@ -155,7 +159,7 @@ export namespace Loci {
 
     export function areIntersecting(xs: Loci, ys: Loci): boolean {
         if (xs.elements.length > ys.elements.length) return areIntersecting(ys, xs);
-        if (xs.elements.length === 0) return ys.elements.length === 0;
+        if (Loci.isEmpty(xs)) return Loci.isEmpty(ys);
 
         const map = new Map<number, OrderedSet<UnitIndex>>();
 
@@ -286,7 +290,7 @@ export namespace Loci {
     }
 
     export function toScriptExpression(loci: Loci) {
-        if (loci.elements.length === 0) return MS.struct.generator.empty();
+        if (Loci.isEmpty(loci)) return MS.struct.generator.empty();
 
         const models = loci.structure.models;
         const sourceIndexMap = new Map<string, { modelLabel: string, modelIndex: number, xs: UniqueArray<number, number> }>();

+ 1 - 1
src/mol-model/structure/structure/element/stats.ts

@@ -92,7 +92,7 @@ export namespace Stats {
 
     export function ofLoci(loci: Loci) {
         const stats = create()
-        if (loci.elements.length > 0) {
+        if (!Loci.isEmpty(loci)) {
             for (const e of loci.elements) handleElement(stats, e)
         }
         return stats

+ 4 - 0
src/mol-model/structure/structure/structure.ts

@@ -468,6 +468,10 @@ namespace Structure {
         return a.structure === b.structure
     }
 
+    export function isLociEmpty(loci: Loci) {
+        return loci.structure.isEmpty
+    }
+
     export function create(units: ReadonlyArray<Unit>, props?: Props): Structure {
         return new Structure(units, props);
     }

+ 4 - 0
src/mol-model/structure/structure/unit/links.ts

@@ -62,6 +62,10 @@ namespace Link {
         return true
     }
 
+    export function isLociEmpty(loci: Loci) {
+        return loci.links.length === 0 ? true : false
+    }
+
     export function remapLoci(loci: Loci, structure: Structure): Loci {
         if (structure === loci.structure) return loci
 

+ 3 - 2
src/mol-plugin/ui/sequence/sequence.tsx

@@ -13,6 +13,7 @@ import { ButtonsType, ModifiersKeys, getButtons, getModifiers } from '../../../m
 import { ValueBox } from '../../../mol-util';
 import { Residue } from './residue';
 import { SequenceWrapper } from './wrapper';
+import { StructureElement } from '../../../mol-model/structure';
 
 type SequenceProps = { sequenceWrapper: SequenceWrapper.Any }
 type SequenceState = { markerData: ValueBox<Uint8Array> }
@@ -62,7 +63,7 @@ export class Sequence<P extends SequenceProps> extends PluginUIComponent<P, Sequ
         const ev = { current: Interactivity.Loci.Empty, modifiers }
         if (seqId !== undefined) {
             const loci = this.props.sequenceWrapper.getLoci(seqId);
-            if (loci.elements.length > 0) ev.current = { loci };
+            if (!StructureElement.Loci.isEmpty(loci)) ev.current = { loci };
         }
         this.plugin.behaviors.interaction.highlight.next(ev)
     }
@@ -71,7 +72,7 @@ export class Sequence<P extends SequenceProps> extends PluginUIComponent<P, Sequ
         const ev = { current: Interactivity.Loci.Empty, buttons, modifiers }
         if (seqId !== undefined) {
             const loci = this.props.sequenceWrapper.getLoci(seqId);
-            if (loci.elements.length > 0) ev.current = { loci };
+            if (!StructureElement.Loci.isEmpty(loci)) ev.current = { loci };
         }
         this.plugin.behaviors.interaction.click.next(ev)
     }

+ 3 - 3
src/mol-plugin/util/structure-element-selection.ts

@@ -69,7 +69,7 @@ class StructureElementSelectionManager {
             if (entry) {
                 entry.selection = StructureElement.Loci.subtract(entry.selection, loci);
                 this.plugin.events.interactivity.selectionUpdated.next()
-                return entry.selection.elements.length === 0 ? EmptyLoci : entry.selection;
+                return StructureElement.Loci.isEmpty(entry.selection) ? EmptyLoci : entry.selection;
             }
         }
         return EmptyLoci
@@ -81,7 +81,7 @@ class StructureElementSelectionManager {
             if (entry) {
                 entry.selection = loci;
                 this.plugin.events.interactivity.selectionUpdated.next()
-                return entry.selection.elements.length === 0 ? EmptyLoci : entry.selection;
+                return StructureElement.Loci.isEmpty(entry.selection) ? EmptyLoci : entry.selection;
             }
         }
         return EmptyLoci;
@@ -94,7 +94,7 @@ class StructureElementSelectionManager {
             const k = keys.next();
             if (k.done) break;
             const s = this.entries.get(k.value)!;
-            if (s.selection.elements.length > 0) selections.push(s.selection);
+            if (!StructureElement.Loci.isEmpty(s.selection)) selections.push(s.selection);
             s.selection = StructureElement.Loci(s.selection.structure, []);
         }
         this.plugin.events.interactivity.selectionUpdated.next()

+ 1 - 1
src/mol-plugin/util/structure-representation-helper.ts

@@ -65,7 +65,7 @@ export class StructureRepresentationHelper {
                 bundle: StructureElement.Bundle.fromLoci(combinedLoci)
             })
         } else {
-            const combinedLoci = getCombinedLoci(modifier, loci, StructureElement.Loci(s, []))
+            const combinedLoci = getCombinedLoci(modifier, loci, StructureElement.Loci.none(s))
             const params = StructureRepresentation3DHelpers.getDefaultParams(this.plugin, type as any, s)
 
             const p = params.type.params

+ 3 - 5
src/mol-repr/structure/complex-representation.ts

@@ -58,11 +58,9 @@ export function ComplexRepresentation<P extends StructureParams>(label: string,
         if (!_structure) return false
         if (!StructureElement.Loci.is(loci) && !Link.isLoci(loci)) return false
         if (!Structure.areRootsEquivalent(loci.structure, _structure)) return false
-        if (StructureElement.Loci.is(loci)) {
-            loci = StructureElement.Loci.remap(loci, _structure)
-        } else if (Link.isLoci(loci)) {
-            loci = Link.remapLoci(loci, _structure)
-        }
+        // Remap `loci` from equivalent structure to the current `_structure`
+        loci = Loci.remap(loci, _structure)
+        if (Loci.isEmpty(loci)) return false
         return visual ? visual.mark(loci, action) : false
     }
 

+ 3 - 7
src/mol-repr/structure/units-representation.ts

@@ -167,13 +167,9 @@ export function UnitsRepresentation<P extends UnitsParams>(label: string, ctx: R
         if (!_structure) return false
         if (!StructureElement.Loci.is(loci) && !Link.isLoci(loci)) return false
         if (!Structure.areRootsEquivalent(loci.structure, _structure)) return false
-        if (StructureElement.Loci.is(loci)) {
-            loci = StructureElement.Loci.remap(loci, _structure)
-            if (loci.elements.length === 0) return false
-        } else if (Link.isLoci(loci)) {
-            loci = Link.remapLoci(loci, _structure)
-            if (loci.links.length === 0) return false
-        }
+        // Remap `loci` from equivalent structure to the current `_structure`
+        loci = Loci.remap(loci, _structure)
+        if (Loci.isEmpty(loci)) return false
         visuals.forEach(({ visual }) => {
             changed = visual.mark(loci, action) || changed
         })