Skip to content
Snippets Groups Projects
Commit bdee4859 authored by Alexander Rose's avatar Alexander Rose
Browse files

generic loci support for overpaint, substance, clipping

parent b5e45aae
No related branches found
No related tags found
No related merge requests found
...@@ -23,6 +23,7 @@ Note that since we don't clearly distinguish between a public and private interf ...@@ -23,6 +23,7 @@ Note that since we don't clearly distinguish between a public and private interf
- Improve checks in in UnitsRepresentation setVisualState - Improve checks in in UnitsRepresentation setVisualState
- Add StructureElement.Loci.forEachLocation - Add StructureElement.Loci.forEachLocation
- Add RepresentationRegistry.clear and ThemeRegistry.clear - Add RepresentationRegistry.clear and ThemeRegistry.clear
- Add generic Loci support for overpaint, substance, clipping themes
## [v3.28.0] - 2022-12-20 ## [v3.28.0] - 2022-12-20
......
/** /**
* Copyright (c) 2019-2021 mol* contributors, licensed under MIT, See LICENSE file for more info. * Copyright (c) 2019-2023 mol* contributors, licensed under MIT, See LICENSE file for more info.
* *
* @author Alexander Rose <alexander.rose@weirdbyte.de> * @author Alexander Rose <alexander.rose@weirdbyte.de>
* @author David Sehnal <david.sehnal@gmail.com> * @author David Sehnal <david.sehnal@gmail.com>
...@@ -61,5 +61,5 @@ async function eachRepr(plugin: PluginContext, components: StructureComponentRef ...@@ -61,5 +61,5 @@ async function eachRepr(plugin: PluginContext, components: StructureComponentRef
function getFilteredBundle(layers: Clipping.BundleLayer[], structure: Structure) { function getFilteredBundle(layers: Clipping.BundleLayer[], structure: Structure) {
const clipping = Clipping.ofBundle(layers, structure.root); const clipping = Clipping.ofBundle(layers, structure.root);
const merged = Clipping.merge(clipping); const merged = Clipping.merge(clipping);
return Clipping.filter(merged, structure); return Clipping.filter(merged, structure) as Clipping<StructureElement.Loci>;
} }
\ No newline at end of file
/** /**
* Copyright (c) 2019-2020 mol* contributors, licensed under MIT, See LICENSE file for more info. * Copyright (c) 2019-2023 mol* contributors, licensed under MIT, See LICENSE file for more info.
* *
* @author Alexander Rose <alexander.rose@weirdbyte.de> * @author Alexander Rose <alexander.rose@weirdbyte.de>
* @author David Sehnal <david.sehnal@gmail.com> * @author David Sehnal <david.sehnal@gmail.com>
...@@ -72,5 +72,5 @@ async function eachRepr(plugin: PluginContext, components: StructureComponentRef ...@@ -72,5 +72,5 @@ async function eachRepr(plugin: PluginContext, components: StructureComponentRef
function getFilteredBundle(layers: Overpaint.BundleLayer[], structure: Structure) { function getFilteredBundle(layers: Overpaint.BundleLayer[], structure: Structure) {
const overpaint = Overpaint.ofBundle(layers, structure.root); const overpaint = Overpaint.ofBundle(layers, structure.root);
const merged = Overpaint.merge(overpaint); const merged = Overpaint.merge(overpaint);
return Overpaint.filter(merged, structure); return Overpaint.filter(merged, structure) as Overpaint<StructureElement.Loci>;
} }
\ No newline at end of file
/** /**
* Copyright (c) 2021 mol* contributors, licensed under MIT, See LICENSE file for more info. * Copyright (c) 2021-2023 mol* contributors, licensed under MIT, See LICENSE file for more info.
* *
* @author Alexander Rose <alexander.rose@weirdbyte.de> * @author Alexander Rose <alexander.rose@weirdbyte.de>
* @author David Sehnal <david.sehnal@gmail.com> * @author David Sehnal <david.sehnal@gmail.com>
...@@ -72,5 +72,5 @@ async function eachRepr(plugin: PluginContext, components: StructureComponentRef ...@@ -72,5 +72,5 @@ async function eachRepr(plugin: PluginContext, components: StructureComponentRef
function getFilteredBundle(layers: Substance.BundleLayer[], structure: Structure) { function getFilteredBundle(layers: Substance.BundleLayer[], structure: Structure) {
const substance = Substance.ofBundle(layers, structure.root); const substance = Substance.ofBundle(layers, structure.root);
const merged = Substance.merge(substance); const merged = Substance.merge(substance);
return Substance.filter(merged, structure); return Substance.filter(merged, structure) as Substance<StructureElement.Loci>;
} }
\ No newline at end of file
/** /**
* Copyright (c) 2020-2021 mol* contributors, licensed under MIT, See LICENSE file for more info. * Copyright (c) 2020-2023 mol* contributors, licensed under MIT, See LICENSE file for more info.
* *
* @author Alexander Rose <alexander.rose@weirdbyte.de> * @author Alexander Rose <alexander.rose@weirdbyte.de>
*/ */
...@@ -11,17 +11,18 @@ import { BitFlags } from '../mol-util/bit-flags'; ...@@ -11,17 +11,18 @@ import { BitFlags } from '../mol-util/bit-flags';
export { Clipping }; export { Clipping };
type Clipping = { type Clipping<T extends Loci = Loci> = {
readonly layers: ReadonlyArray<Clipping.Layer> readonly kind: T['kind']
readonly layers: ReadonlyArray<Clipping.Layer<T>>
} }
function Clipping(layers: Clipping['layers']): Clipping { function Clipping<T extends Loci>(kind: T['kind'], layers: ReadonlyArray<Clipping.Layer<T>>): Clipping<T> {
return { layers }; return { kind, layers };
} }
namespace Clipping { namespace Clipping {
export type Layer = { readonly loci: StructureElement.Loci, readonly groups: Groups } export type Layer<T extends Loci = Loci> = { readonly loci: T, readonly groups: Groups }
export const Empty: Clipping = { layers: [] }; export const Empty: Clipping = { kind: 'empty-loci', layers: [] };
export type Groups = BitFlags<Groups.Flag> export type Groups = BitFlags<Groups.Flag>
export namespace Groups { export namespace Groups {
...@@ -101,57 +102,69 @@ namespace Clipping { ...@@ -101,57 +102,69 @@ namespace Clipping {
/** Remap layers */ /** Remap layers */
export function remap(clipping: Clipping, structure: Structure): Clipping { export function remap(clipping: Clipping, structure: Structure): Clipping {
const layers: Clipping.Layer[] = []; if (clipping.kind === 'element-loci') {
for (const layer of clipping.layers) { const layers: Clipping.Layer[] = [];
let { loci, groups } = layer; for (const layer of clipping.layers) {
loci = StructureElement.Loci.remap(loci, structure); let { loci, groups } = layer;
if (!StructureElement.Loci.isEmpty(loci)) { loci = StructureElement.Loci.remap(loci as StructureElement.Loci, structure);
layers.push({ loci, groups }); if (!StructureElement.Loci.isEmpty(loci)) {
layers.push({ loci, groups });
}
} }
return { kind: 'element-loci', layers };
} else {
return clipping;
} }
return { layers };
} }
/** Merge layers */ /** Merge layers */
export function merge(clipping: Clipping): Clipping { export function merge(clipping: Clipping): Clipping {
if (isEmpty(clipping)) return clipping; if (isEmpty(clipping)) return clipping;
const { structure } = clipping.layers[0].loci; if (clipping.kind === 'element-loci') {
const map = new Map<Groups, StructureElement.Loci>(); const { structure } = clipping.layers[0].loci as StructureElement.Loci;
let shadowed = StructureElement.Loci.none(structure); const map = new Map<Groups, StructureElement.Loci>();
for (let i = 0, il = clipping.layers.length; i < il; ++i) { let shadowed = StructureElement.Loci.none(structure);
let { loci, groups } = clipping.layers[il - i - 1]; // process from end for (let i = 0, il = clipping.layers.length; i < il; ++i) {
loci = StructureElement.Loci.subtract(loci, shadowed); let { loci, groups } = clipping.layers[il - i - 1]; // process from end
shadowed = StructureElement.Loci.union(loci, shadowed); loci = StructureElement.Loci.subtract(loci as StructureElement.Loci, shadowed);
if (!StructureElement.Loci.isEmpty(loci)) { shadowed = StructureElement.Loci.union(loci, shadowed);
if (map.has(groups)) { if (!StructureElement.Loci.isEmpty(loci)) {
loci = StructureElement.Loci.union(loci, map.get(groups)!); if (map.has(groups)) {
loci = StructureElement.Loci.union(loci, map.get(groups)!);
}
map.set(groups, loci);
} }
map.set(groups, loci);
} }
const layers: Clipping.Layer[] = [];
map.forEach((loci, groups) => {
layers.push({ loci, groups });
});
return { kind: 'element-loci', layers };
} else {
return clipping;
} }
const layers: Clipping.Layer[] = [];
map.forEach((loci, groups) => {
layers.push({ loci, groups });
});
return { layers };
} }
/** Filter layers */ /** Filter layers */
export function filter(clipping: Clipping, filter: Structure): Clipping { export function filter(clipping: Clipping, filter: Structure): Clipping {
if (isEmpty(clipping)) return clipping; if (isEmpty(clipping)) return clipping;
const { structure } = clipping.layers[0].loci; if (clipping.kind === 'element-loci') {
const layers: Clipping.Layer[] = []; const { structure } = clipping.layers[0].loci as StructureElement.Loci;
for (const layer of clipping.layers) { const layers: Clipping.Layer[] = [];
let { loci, groups } = layer; for (const layer of clipping.layers) {
// filter by first map to the `filter` structure and let { loci, groups } = layer;
// then map back to the original structure of the clipping loci // filter by first map to the `filter` structure and
const filtered = StructureElement.Loci.remap(loci, filter); // then map back to the original structure of the clipping loci
loci = StructureElement.Loci.remap(filtered, structure); const filtered = StructureElement.Loci.remap(loci as StructureElement.Loci, filter);
if (!StructureElement.Loci.isEmpty(loci)) { loci = StructureElement.Loci.remap(filtered, structure);
layers.push({ loci, groups }); if (!StructureElement.Loci.isEmpty(loci)) {
layers.push({ loci, groups });
}
} }
return { kind: 'element-loci', layers };
} else {
return clipping;
} }
return { layers };
} }
export type ScriptLayer = { script: Script, groups: Groups } export type ScriptLayer = { script: Script, groups: Groups }
...@@ -164,7 +177,7 @@ namespace Clipping { ...@@ -164,7 +177,7 @@ namespace Clipping {
layers.push({ loci, groups }); layers.push({ loci, groups });
} }
} }
return { layers }; return { kind: 'element-loci', layers };
} }
export type BundleLayer = { bundle: StructureElement.Bundle, groups: Groups } export type BundleLayer = { bundle: StructureElement.Bundle, groups: Groups }
...@@ -175,16 +188,16 @@ namespace Clipping { ...@@ -175,16 +188,16 @@ namespace Clipping {
const loci = StructureElement.Bundle.toLoci(bundle, structure.root); const loci = StructureElement.Bundle.toLoci(bundle, structure.root);
layers.push({ loci, groups }); layers.push({ loci, groups });
} }
return { layers }; return { kind: 'element-loci', layers };
} }
export function toBundle(clipping: Clipping) { export function toBundle(clipping: Clipping<StructureElement.Loci>) {
const layers: BundleLayer[] = []; const layers: BundleLayer[] = [];
for (let i = 0, il = clipping.layers.length; i < il; ++i) { for (let i = 0, il = clipping.layers.length; i < il; ++i) {
const { loci, groups } = clipping.layers[i]; const { loci, groups } = clipping.layers[i];
const bundle = StructureElement.Bundle.fromLoci(loci); const bundle = StructureElement.Bundle.fromLoci(loci);
layers.push({ bundle, groups }); layers.push({ bundle, groups });
} }
return { layers }; return { kind: 'element-loci', layers };
} }
} }
\ No newline at end of file
/** /**
* Copyright (c) 2019-2020 mol* contributors, licensed under MIT, See LICENSE file for more info. * Copyright (c) 2019-2023 mol* contributors, licensed under MIT, See LICENSE file for more info.
* *
* @author Alexander Rose <alexander.rose@weirdbyte.de> * @author Alexander Rose <alexander.rose@weirdbyte.de>
*/ */
...@@ -11,15 +11,18 @@ import { Script } from '../mol-script/script'; ...@@ -11,15 +11,18 @@ import { Script } from '../mol-script/script';
export { Overpaint }; export { Overpaint };
type Overpaint = { readonly layers: ReadonlyArray<Overpaint.Layer> } type Overpaint<T extends Loci = Loci> = {
readonly kind: T['kind']
readonly layers: ReadonlyArray<Overpaint.Layer<T>>
}
function Overpaint(layers: ReadonlyArray<Overpaint.Layer>): Overpaint { function Overpaint<T extends Loci>(kind: T['kind'], layers: ReadonlyArray<Overpaint.Layer<T>>): Overpaint<T> {
return { layers }; return { kind, layers };
} }
namespace Overpaint { namespace Overpaint {
export type Layer = { readonly loci: StructureElement.Loci, readonly color: Color, readonly clear: boolean } export type Layer<T extends Loci = Loci> = { readonly loci: T, readonly color: Color, readonly clear: boolean }
export const Empty: Overpaint = { layers: [] }; export const Empty: Overpaint = { kind: 'empty-loci', layers: [] };
export function areEqual(oA: Overpaint, oB: Overpaint) { export function areEqual(oA: Overpaint, oB: Overpaint) {
if (oA.layers.length === 0 && oB.layers.length === 0) return true; if (oA.layers.length === 0 && oB.layers.length === 0) return true;
...@@ -36,59 +39,71 @@ namespace Overpaint { ...@@ -36,59 +39,71 @@ namespace Overpaint {
return overpaint.layers.length === 0; return overpaint.layers.length === 0;
} }
export function remap(overpaint: Overpaint, structure: Structure) { export function remap(overpaint: Overpaint, structure: Structure): Overpaint {
const layers: Overpaint.Layer[] = []; if (overpaint.kind === 'element-loci') {
for (const layer of overpaint.layers) { const layers: Overpaint.Layer[] = [];
let { loci, color, clear } = layer; for (const layer of overpaint.layers) {
loci = StructureElement.Loci.remap(loci, structure); let { loci, color, clear } = layer;
if (!StructureElement.Loci.isEmpty(loci)) { loci = StructureElement.Loci.remap(loci as StructureElement.Loci, structure);
layers.push({ loci, color, clear }); if (!StructureElement.Loci.isEmpty(loci)) {
layers.push({ loci, color, clear });
}
} }
return { kind: 'element-loci', layers };
} else {
return overpaint;
} }
return { layers };
} }
export function merge(overpaint: Overpaint): Overpaint { export function merge(overpaint: Overpaint): Overpaint {
if (isEmpty(overpaint)) return overpaint; if (isEmpty(overpaint)) return overpaint;
const { structure } = overpaint.layers[0].loci; if (overpaint.kind === 'element-loci') {
const map = new Map<Color | -1, StructureElement.Loci>(); const { structure } = overpaint.layers[0].loci as StructureElement.Loci;
let shadowed = StructureElement.Loci.none(structure); const map = new Map<Color | -1, StructureElement.Loci>();
for (let i = 0, il = overpaint.layers.length; i < il; ++i) { let shadowed = StructureElement.Loci.none(structure);
let { loci, color, clear } = overpaint.layers[il - i - 1]; // process from end for (let i = 0, il = overpaint.layers.length; i < il; ++i) {
loci = StructureElement.Loci.subtract(loci, shadowed); let { loci, color, clear } = overpaint.layers[il - i - 1]; // process from end
shadowed = StructureElement.Loci.union(loci, shadowed); loci = StructureElement.Loci.subtract(loci as StructureElement.Loci, shadowed);
if (!StructureElement.Loci.isEmpty(loci)) { shadowed = StructureElement.Loci.union(loci, shadowed);
const colorOrClear = clear ? -1 : color; if (!StructureElement.Loci.isEmpty(loci)) {
if (map.has(colorOrClear)) { const colorOrClear = clear ? -1 : color;
loci = StructureElement.Loci.union(loci, map.get(colorOrClear)!); if (map.has(colorOrClear)) {
loci = StructureElement.Loci.union(loci, map.get(colorOrClear)!);
}
map.set(colorOrClear, loci);
} }
map.set(colorOrClear, loci);
} }
const layers: Overpaint.Layer[] = [];
map.forEach((loci, colorOrClear) => {
const clear = colorOrClear === -1;
const color = clear ? Color(0) : colorOrClear;
layers.push({ loci, color, clear });
});
return { kind: 'element-loci', layers };
} else {
return overpaint;
} }
const layers: Overpaint.Layer[] = [];
map.forEach((loci, colorOrClear) => {
const clear = colorOrClear === -1;
const color = clear ? Color(0) : colorOrClear;
layers.push({ loci, color, clear });
});
return { layers };
} }
export function filter(overpaint: Overpaint, filter: Structure): Overpaint { export function filter(overpaint: Overpaint, filter: Structure): Overpaint {
if (isEmpty(overpaint)) return overpaint; if (isEmpty(overpaint)) return overpaint;
const { structure } = overpaint.layers[0].loci; if (overpaint.kind === 'element-loci') {
const layers: Overpaint.Layer[] = []; const { structure } = overpaint.layers[0].loci as StructureElement.Loci;
for (const layer of overpaint.layers) { const layers: Overpaint.Layer[] = [];
let { loci, color, clear } = layer; for (const layer of overpaint.layers) {
// filter by first map to the `filter` structure and let { loci, color, clear } = layer;
// then map back to the original structure of the overpaint loci // filter by first map to the `filter` structure and
const filtered = StructureElement.Loci.remap(loci, filter); // then map back to the original structure of the overpaint loci
loci = StructureElement.Loci.remap(filtered, structure); const filtered = StructureElement.Loci.remap(loci as StructureElement.Loci, filter);
if (!StructureElement.Loci.isEmpty(loci)) { loci = StructureElement.Loci.remap(filtered, structure);
layers.push({ loci, color, clear }); if (!StructureElement.Loci.isEmpty(loci)) {
layers.push({ loci, color, clear });
}
} }
return { kind: 'element-loci', layers };
} else {
return overpaint;
} }
return { layers };
} }
export type ScriptLayer = { script: Script, color: Color, clear: boolean } export type ScriptLayer = { script: Script, color: Color, clear: boolean }
...@@ -101,7 +116,7 @@ namespace Overpaint { ...@@ -101,7 +116,7 @@ namespace Overpaint {
layers.push({ loci, color, clear }); layers.push({ loci, color, clear });
} }
} }
return { layers }; return { kind: 'element-loci', layers };
} }
export type BundleLayer = { bundle: StructureElement.Bundle, color: Color, clear: boolean } export type BundleLayer = { bundle: StructureElement.Bundle, color: Color, clear: boolean }
...@@ -112,16 +127,16 @@ namespace Overpaint { ...@@ -112,16 +127,16 @@ namespace Overpaint {
const loci = StructureElement.Bundle.toLoci(bundle, structure.root); const loci = StructureElement.Bundle.toLoci(bundle, structure.root);
layers.push({ loci, color, clear }); layers.push({ loci, color, clear });
} }
return { layers }; return { kind: 'element-loci', layers };
} }
export function toBundle(overpaint: Overpaint) { export function toBundle(overpaint: Overpaint<StructureElement.Loci>) {
const layers: BundleLayer[] = []; const layers: BundleLayer[] = [];
for (let i = 0, il = overpaint.layers.length; i < il; ++i) { for (let i = 0, il = overpaint.layers.length; i < il; ++i) {
const { loci, color, clear } = overpaint.layers[i]; const { loci, color, clear } = overpaint.layers[i];
const bundle = StructureElement.Bundle.fromLoci(loci); const bundle = StructureElement.Bundle.fromLoci(loci);
layers.push({ bundle, color, clear }); layers.push({ bundle, color, clear });
} }
return { layers }; return { kind: 'element-loci', layers };
} }
} }
\ No newline at end of file
/** /**
* Copyright (c) 2021 mol* contributors, licensed under MIT, See LICENSE file for more info. * Copyright (c) 2021-2023 mol* contributors, licensed under MIT, See LICENSE file for more info.
* *
* @author Alexander Rose <alexander.rose@weirdbyte.de> * @author Alexander Rose <alexander.rose@weirdbyte.de>
*/ */
...@@ -12,15 +12,18 @@ import { shallowEqual } from '../mol-util/object'; ...@@ -12,15 +12,18 @@ import { shallowEqual } from '../mol-util/object';
export { Substance }; export { Substance };
type Substance = { readonly layers: ReadonlyArray<Substance.Layer> } type Substance<T extends Loci = Loci> = {
readonly kind: T['kind']
readonly layers: ReadonlyArray<Substance.Layer<T>>
}
function Substance(layers: ReadonlyArray<Substance.Layer>): Substance { function Substance<T extends Loci>(kind: T['kind'], layers: ReadonlyArray<Substance.Layer<T>>): Substance {
return { layers }; return { kind, layers };
} }
namespace Substance { namespace Substance {
export type Layer = { readonly loci: StructureElement.Loci, readonly material: Material, readonly clear: boolean } export type Layer<T extends Loci = Loci> = { readonly loci: T, readonly material: Material, readonly clear: boolean }
export const Empty: Substance = { layers: [] }; export const Empty: Substance = { kind: 'empty-loci', layers: [] };
export function areEqual(sA: Substance, sB: Substance) { export function areEqual(sA: Substance, sB: Substance) {
if (sA.layers.length === 0 && sB.layers.length === 0) return true; if (sA.layers.length === 0 && sB.layers.length === 0) return true;
...@@ -37,66 +40,78 @@ namespace Substance { ...@@ -37,66 +40,78 @@ namespace Substance {
return overpaint.layers.length === 0; return overpaint.layers.length === 0;
} }
export function remap(substance: Substance, structure: Structure) { export function remap(substance: Substance, structure: Structure): Substance {
const layers: Substance.Layer[] = []; if (substance.kind === 'element-loci') {
for (const layer of substance.layers) { const layers: Substance.Layer[] = [];
let { loci, material, clear } = layer; for (const layer of substance.layers) {
loci = StructureElement.Loci.remap(loci, structure); let { loci, material, clear } = layer;
if (!StructureElement.Loci.isEmpty(loci)) { loci = StructureElement.Loci.remap(loci as StructureElement.Loci, structure);
layers.push({ loci, material, clear }); if (!StructureElement.Loci.isEmpty(loci)) {
layers.push({ loci, material, clear });
}
} }
return { kind: 'element-loci', layers };
} else {
return substance;
} }
return { layers };
} }
export function merge(substance: Substance): Substance { export function merge(substance: Substance): Substance {
if (isEmpty(substance)) return substance; if (isEmpty(substance)) return substance;
const { structure } = substance.layers[0].loci; if (substance.kind === 'element-loci') {
let clearLoci: StructureElement.Loci | undefined = void 0; const { structure } = substance.layers[0].loci as StructureElement.Loci;
const map = new Map<Material, StructureElement.Loci>(); let clearLoci: StructureElement.Loci | undefined = void 0;
let shadowed = StructureElement.Loci.none(structure); const map = new Map<Material, StructureElement.Loci>();
for (let i = 0, il = substance.layers.length; i < il; ++i) { let shadowed = StructureElement.Loci.none(structure);
let { loci, material, clear } = substance.layers[il - i - 1]; // process from end for (let i = 0, il = substance.layers.length; i < il; ++i) {
loci = StructureElement.Loci.subtract(loci, shadowed); let { loci, material, clear } = substance.layers[il - i - 1]; // process from end
shadowed = StructureElement.Loci.union(loci, shadowed); loci = StructureElement.Loci.subtract(loci as StructureElement.Loci, shadowed);
if (!StructureElement.Loci.isEmpty(loci)) { shadowed = StructureElement.Loci.union(loci, shadowed);
if (clear) { if (!StructureElement.Loci.isEmpty(loci)) {
clearLoci = clearLoci if (clear) {
? StructureElement.Loci.union(loci, clearLoci) clearLoci = clearLoci
: loci; ? StructureElement.Loci.union(loci, clearLoci)
} else { : loci;
if (map.has(material)) { } else {
loci = StructureElement.Loci.union(loci, map.get(material)!); if (map.has(material)) {
loci = StructureElement.Loci.union(loci, map.get(material)!);
}
map.set(material, loci);
} }
map.set(material, loci);
} }
} }
const layers: Substance.Layer[] = [];
if (clearLoci) {
layers.push({ loci: clearLoci, material: Material(), clear: true });
}
map.forEach((loci, material) => {
layers.push({ loci, material, clear: false });
});
return { kind: 'element-loci', layers };
} else {
return substance;
} }
const layers: Substance.Layer[] = [];
if (clearLoci) {
layers.push({ loci: clearLoci, material: Material(), clear: true });
}
map.forEach((loci, material) => {
layers.push({ loci, material, clear: false });
});
return { layers };
} }
export function filter(substance: Substance, filter: Structure): Substance { export function filter(substance: Substance, filter: Structure): Substance {
if (isEmpty(substance)) return substance; if (isEmpty(substance)) return substance;
const { structure } = substance.layers[0].loci; if (substance.kind === 'element-loci') {
const layers: Substance.Layer[] = []; const { structure } = substance.layers[0].loci as StructureElement.Loci;
for (const layer of substance.layers) { const layers: Substance.Layer[] = [];
let { loci, material, clear } = layer; for (const layer of substance.layers) {
// filter by first map to the `filter` structure and let { loci, material, clear } = layer;
// then map back to the original structure of the substance loci // filter by first map to the `filter` structure and
const filtered = StructureElement.Loci.remap(loci, filter); // then map back to the original structure of the substance loci
loci = StructureElement.Loci.remap(filtered, structure); const filtered = StructureElement.Loci.remap(loci as StructureElement.Loci, filter);
if (!StructureElement.Loci.isEmpty(loci)) { loci = StructureElement.Loci.remap(filtered, structure);
layers.push({ loci, material, clear }); if (!StructureElement.Loci.isEmpty(loci)) {
layers.push({ loci, material, clear });
}
} }
return { kind: 'element-loci', layers };
} else {
return substance;
} }
return { layers };
} }
export type ScriptLayer = { script: Script, material: Material, clear: boolean } export type ScriptLayer = { script: Script, material: Material, clear: boolean }
...@@ -109,7 +124,7 @@ namespace Substance { ...@@ -109,7 +124,7 @@ namespace Substance {
layers.push({ loci, material, clear }); layers.push({ loci, material, clear });
} }
} }
return { layers }; return { kind: 'element-loci', layers };
} }
export type BundleLayer = { bundle: StructureElement.Bundle, material: Material, clear: boolean } export type BundleLayer = { bundle: StructureElement.Bundle, material: Material, clear: boolean }
...@@ -120,16 +135,16 @@ namespace Substance { ...@@ -120,16 +135,16 @@ namespace Substance {
const loci = StructureElement.Bundle.toLoci(bundle, structure.root); const loci = StructureElement.Bundle.toLoci(bundle, structure.root);
layers.push({ loci, material, clear }); layers.push({ loci, material, clear });
} }
return { layers }; return { kind: 'element-loci', layers };
} }
export function toBundle(overpaint: Substance) { export function toBundle(overpaint: Substance<StructureElement.Loci>) {
const layers: BundleLayer[] = []; const layers: BundleLayer[] = [];
for (let i = 0, il = overpaint.layers.length; i < il; ++i) { for (let i = 0, il = overpaint.layers.length; i < il; ++i) {
const { loci, material, clear } = overpaint.layers[i]; const { loci, material, clear } = overpaint.layers[i];
const bundle = StructureElement.Bundle.fromLoci(loci); const bundle = StructureElement.Bundle.fromLoci(loci);
layers.push({ bundle, material, clear }); layers.push({ bundle, material, clear });
} }
return { layers }; return { kind: 'element-loci', layers };
} }
} }
\ No newline at end of file
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment