|
@@ -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 };
|
|
|
}
|
|
|
}
|