Przeglądaj źródła

made transparency helpers a bit more generic

Alexander Rose 3 lat temu
rodzic
commit
c436653ce9

+ 2 - 2
src/mol-plugin-state/helpers/structure-transparency.ts

@@ -1,5 +1,5 @@
 /**
- * Copyright (c) 2019-2020 mol* contributors, licensed under MIT, See LICENSE file for more info.
+ * Copyright (c) 2019-2021 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>
@@ -70,5 +70,5 @@ async function eachRepr(plugin: PluginContext, components: StructureComponentRef
 function getFilteredBundle(layers: Transparency.BundleLayer[], structure: Structure) {
     const transparency = Transparency.ofBundle(layers, structure.root);
     const merged = Transparency.merge(transparency);
-    return Transparency.filter(merged, structure);
+    return Transparency.filter(merged, structure) as Transparency<StructureElement.Loci>;
 }

+ 63 - 49
src/mol-theme/transparency.ts

@@ -1,5 +1,5 @@
 /**
- * Copyright (c) 2019-2020 mol* contributors, licensed under MIT, See LICENSE file for more info.
+ * Copyright (c) 2019-2021 mol* contributors, licensed under MIT, See LICENSE file for more info.
  *
  * @author Alexander Rose <alexander.rose@weirdbyte.de>
  */
@@ -10,15 +10,18 @@ import { Script } from '../mol-script/script';
 
 export { Transparency };
 
-type Transparency = { readonly layers: ReadonlyArray<Transparency.Layer> }
+type Transparency<T extends Loci = Loci> = {
+    readonly kind: T['kind']
+    readonly layers: ReadonlyArray<Transparency.Layer<T>>
+}
 
-function Transparency(layers: ReadonlyArray<Transparency.Layer>): Transparency {
-    return { layers };
+function Transparency<T extends Loci>(kind: T['kind'], layers: ReadonlyArray<Transparency.Layer<T>>): Transparency<T> {
+    return { kind, layers };
 }
 
 namespace Transparency {
-    export type Layer = { readonly loci: StructureElement.Loci, readonly value: number }
-    export const Empty: Transparency = { layers: [] };
+    export type Layer<T extends Loci = Loci> = { readonly loci: T, readonly value: number }
+    export const Empty: Transparency = { kind: 'empty-loci', layers: [] };
 
     export type Variant = 'single' | 'multi'
 
@@ -36,61 +39,72 @@ namespace Transparency {
         return transparency.layers.length === 0;
     }
 
-    export function remap(transparency: Transparency, structure: Structure) {
-        const layers: Transparency.Layer[] = [];
-        for (const layer of transparency.layers) {
-            let { loci, value } = layer;
-            loci = StructureElement.Loci.remap(loci, structure);
-            if (!StructureElement.Loci.isEmpty(loci)) {
-                layers.push({ loci, value });
+    export function remap(transparency: Transparency, structure: Structure): Transparency {
+        if (transparency.kind === 'element-loci') {
+            const layers: Transparency.Layer[] = [];
+            for (const layer of transparency.layers) {
+                const loci = StructureElement.Loci.remap(layer.loci as StructureElement.Loci, structure);
+                if (!StructureElement.Loci.isEmpty(loci)) {
+                    layers.push({ loci, value: layer.value });
+                }
             }
+            return { kind: 'element-loci', layers };
+        } else {
+            return transparency;
         }
-        return { layers };
     }
 
     export function merge(transparency: Transparency): Transparency {
         if (isEmpty(transparency)) return transparency;
-        const { structure } = transparency.layers[0].loci;
-        const map = new Map<number, StructureElement.Loci>();
-        let shadowed = StructureElement.Loci.none(structure);
-        for (let i = 0, il = transparency.layers.length; i < il; ++i) {
-            let { loci, value } = transparency.layers[il - i - 1]; // process from end
-            loci = StructureElement.Loci.subtract(loci, shadowed);
-            shadowed = StructureElement.Loci.union(loci, shadowed);
-            if (!StructureElement.Loci.isEmpty(loci)) {
-                if (map.has(value)) {
-                    loci = StructureElement.Loci.union(loci, map.get(value)!);
+        if (transparency.kind === 'element-loci') {
+            const { structure } = transparency.layers[0].loci as StructureElement.Loci;
+            const map = new Map<number, StructureElement.Loci>();
+            let shadowed = StructureElement.Loci.none(structure);
+            for (let i = 0, il = transparency.layers.length; i < il; ++i) {
+                let { loci, value } = transparency.layers[il - i - 1]; // process from end
+                loci = StructureElement.Loci.subtract(loci as StructureElement.Loci, shadowed);
+                shadowed = StructureElement.Loci.union(loci, shadowed);
+                if (!StructureElement.Loci.isEmpty(loci)) {
+                    if (map.has(value)) {
+                        loci = StructureElement.Loci.union(loci, map.get(value)!);
+                    }
+                    map.set(value, loci);
                 }
-                map.set(value, loci);
             }
+            const layers: Transparency.Layer<StructureElement.Loci>[] = [];
+            map.forEach((loci, value) => {
+                layers.push({ loci, value });
+            });
+            return { kind: 'element-loci', layers };
+        } else {
+            return transparency;
         }
-        const layers: Transparency.Layer[] = [];
-        map.forEach((loci, value) => {
-            layers.push({ loci, value });
-        });
-        return { layers };
     }
 
     export function filter(transparency: Transparency, filter: Structure): Transparency {
         if (isEmpty(transparency)) return transparency;
-        const { structure } = transparency.layers[0].loci;
-        const layers: Transparency.Layer[] = [];
-        for (const layer of transparency.layers) {
-            let { loci, value } = layer;
-            // filter by first map to the `filter` structure and
-            // then map back to the original structure of the transparency loci
-            const filtered = StructureElement.Loci.remap(loci, filter);
-            loci = StructureElement.Loci.remap(filtered, structure);
-            if (!StructureElement.Loci.isEmpty(loci)) {
-                layers.push({ loci, value });
+        if (transparency.kind === 'element-loci') {
+            const { structure } = transparency.layers[0].loci as StructureElement.Loci;
+            const layers: Transparency.Layer<StructureElement.Loci>[] = [];
+            for (const layer of transparency.layers) {
+                let { loci, value } = layer;
+                // filter by first map to the `filter` structure and
+                // then map back to the original structure of the transparency loci
+                const filtered = StructureElement.Loci.remap(loci as StructureElement.Loci, filter);
+                loci = StructureElement.Loci.remap(filtered, structure);
+                if (!StructureElement.Loci.isEmpty(loci)) {
+                    layers.push({ loci, value });
+                }
             }
+            return { kind: 'element-loci', layers };
+        } else {
+            return transparency;
         }
-        return { layers };
     }
 
     export type ScriptLayer = { script: Script, value: number }
-    export function ofScript(scriptLayers: ScriptLayer[], structure: Structure): Transparency {
-        const layers: Transparency.Layer[] = [];
+    export function ofScript(scriptLayers: ScriptLayer[], structure: Structure): Transparency<StructureElement.Loci> {
+        const layers: Transparency.Layer<StructureElement.Loci>[] = [];
         for (let i = 0, il = scriptLayers.length; i < il; ++i) {
             const { script, value } = scriptLayers[i];
             const loci = Script.toLoci(script, structure);
@@ -98,27 +112,27 @@ namespace Transparency {
                 layers.push({ loci, value });
             }
         }
-        return { layers };
+        return { kind: 'element-loci', layers };
     }
 
     export type BundleLayer = { bundle: StructureElement.Bundle, value: number }
-    export function ofBundle(bundleLayers: BundleLayer[], structure: Structure): Transparency {
-        const layers: Transparency.Layer[] = [];
+    export function ofBundle(bundleLayers: BundleLayer[], structure: Structure): Transparency<StructureElement.Loci> {
+        const layers: Transparency.Layer<StructureElement.Loci>[] = [];
         for (let i = 0, il = bundleLayers.length; i < il; ++i) {
             const { bundle, value } = bundleLayers[i];
             const loci = StructureElement.Bundle.toLoci(bundle, structure.root);
             layers.push({ loci, value });
         }
-        return { layers };
+        return { kind: 'element-loci', layers };
     }
 
-    export function toBundle(transparency: Transparency) {
+    export function toBundle(transparency: Transparency<StructureElement.Loci>) {
         const layers: BundleLayer[] = [];
         for (let i = 0, il = transparency.layers.length; i < il; ++i) {
             let { loci, value } = transparency.layers[i];
             const bundle = StructureElement.Bundle.fromLoci(loci);
             layers.push({ bundle, value });
         }
-        return { layers };
+        return { kind: 'element-loci', layers };
     }
 }