123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190 |
- /**
- * Copyright (c) 2020-2021 mol* contributors, licensed under MIT, See LICENSE file for more info.
- *
- * @author Alexander Rose <alexander.rose@weirdbyte.de>
- */
- import { Loci } from '../mol-model/loci';
- import { StructureElement, Structure } from '../mol-model/structure';
- import { Script } from '../mol-script/script';
- import { BitFlags } from '../mol-util/bit-flags';
- export { Clipping };
- type Clipping = {
- readonly layers: ReadonlyArray<Clipping.Layer>
- }
- function Clipping(layers: Clipping['layers']): Clipping {
- return { layers };
- }
- namespace Clipping {
- export type Layer = { readonly loci: StructureElement.Loci, readonly groups: Groups }
- export const Empty: Clipping = { layers: [] };
- export type Groups = BitFlags<Groups.Flag>
- export namespace Groups {
- export const is: (g: Groups, f: Flag) => boolean = BitFlags.has;
- export const enum Flag {
- None = 0x0,
- One = 0x1,
- Two = 0x2,
- Three = 0x4,
- Four = 0x8,
- Five = 0x10,
- Six = 0x20,
- }
- export function create(flags: Flag): Groups {
- return BitFlags.create(flags);
- }
- export const Names = {
- 'one': Flag.One,
- 'two': Flag.Two,
- 'three': Flag.Three,
- 'four': Flag.Four,
- 'five': Flag.Five,
- 'six': Flag.Six,
- };
- export type Names = keyof typeof Names
- export function isName(name: string): name is Names {
- return name in Names;
- }
- export function fromName(name: Names): Flag {
- switch (name) {
- case 'one': return Flag.One;
- case 'two': return Flag.Two;
- case 'three': return Flag.Three;
- case 'four': return Flag.Four;
- case 'five': return Flag.Five;
- case 'six': return Flag.Six;
- }
- }
- export function fromNames(names: Names[]): Flag {
- let f = Flag.None;
- for (let i = 0, il = names.length; i < il; ++i) {
- f |= fromName(names[i]);
- }
- return f;
- }
- export function toNames(groups: Groups): Names[] {
- const names: Names[] = [];
- if (is(groups, Flag.One)) names.push('one');
- if (is(groups, Flag.Two)) names.push('two');
- if (is(groups, Flag.Three)) names.push('three');
- if (is(groups, Flag.Four)) names.push('four');
- if (is(groups, Flag.Five)) names.push('five');
- if (is(groups, Flag.Six)) names.push('six');
- return names;
- }
- }
- export function areEqual(cA: Clipping, cB: Clipping) {
- if (cA.layers.length !== cB.layers.length) return false;
- for (let i = 0, il = cA.layers.length; i < il; ++i) {
- if (cA.layers[i].groups !== cB.layers[i].groups) return false;
- if (!Loci.areEqual(cA.layers[i].loci, cB.layers[i].loci)) return false;
- }
- return true;
- }
- /** Check if layers empty */
- export function isEmpty(clipping: Clipping) {
- return clipping.layers.length === 0;
- }
- /** Remap layers */
- export function remap(clipping: Clipping, structure: Structure): Clipping {
- const layers: Clipping.Layer[] = [];
- for (const layer of clipping.layers) {
- let { loci, groups } = layer;
- loci = StructureElement.Loci.remap(loci, structure);
- if (!StructureElement.Loci.isEmpty(loci)) {
- layers.push({ loci, groups });
- }
- }
- return { layers };
- }
- /** Merge layers */
- export function merge(clipping: Clipping): Clipping {
- if (isEmpty(clipping)) return clipping;
- const { structure } = clipping.layers[0].loci;
- const map = new Map<Groups, StructureElement.Loci>();
- let shadowed = StructureElement.Loci.none(structure);
- for (let i = 0, il = clipping.layers.length; i < il; ++i) {
- let { loci, groups } = clipping.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(groups)) {
- loci = StructureElement.Loci.union(loci, map.get(groups)!);
- }
- map.set(groups, loci);
- }
- }
- const layers: Clipping.Layer[] = [];
- map.forEach((loci, groups) => {
- layers.push({ loci, groups });
- });
- return { layers };
- }
- /** Filter layers */
- export function filter(clipping: Clipping, filter: Structure): Clipping {
- if (isEmpty(clipping)) return clipping;
- const { structure } = clipping.layers[0].loci;
- const layers: Clipping.Layer[] = [];
- for (const layer of clipping.layers) {
- let { loci, groups } = layer;
- // filter by first map to the `filter` structure and
- // then map back to the original structure of the clipping loci
- const filtered = StructureElement.Loci.remap(loci, filter);
- loci = StructureElement.Loci.remap(filtered, structure);
- if (!StructureElement.Loci.isEmpty(loci)) {
- layers.push({ loci, groups });
- }
- }
- return { layers };
- }
- export type ScriptLayer = { script: Script, groups: Groups }
- export function ofScript(scriptLayers: ScriptLayer[], structure: Structure): Clipping {
- const layers: Clipping.Layer[] = [];
- for (let i = 0, il = scriptLayers.length; i < il; ++i) {
- const { script, groups } = scriptLayers[i];
- const loci = Script.toLoci(script, structure);
- if (!StructureElement.Loci.isEmpty(loci)) {
- layers.push({ loci, groups });
- }
- }
- return { layers };
- }
- export type BundleLayer = { bundle: StructureElement.Bundle, groups: Groups }
- export function ofBundle(bundleLayers: BundleLayer[], structure: Structure): Clipping {
- const layers: Clipping.Layer[] = [];
- for (let i = 0, il = bundleLayers.length; i < il; ++i) {
- const { bundle, groups } = bundleLayers[i];
- const loci = StructureElement.Bundle.toLoci(bundle, structure.root);
- layers.push({ loci, groups });
- }
- return { layers };
- }
- export function toBundle(clipping: Clipping) {
- const layers: BundleLayer[] = [];
- for (let i = 0, il = clipping.layers.length; i < il; ++i) {
- const { loci, groups } = clipping.layers[i];
- const bundle = StructureElement.Bundle.fromLoci(loci);
- layers.push({ bundle, groups });
- }
- return { layers };
- }
- }
|