123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128 |
- /**
- * Copyright (c) 2019 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 { Color } from '../mol-util/color';
- import { Structure, StructureElement } from '../mol-model/structure';
- import { Script } from '../mol-script/script';
- export { Overpaint }
- type Overpaint = { readonly layers: ReadonlyArray<Overpaint.Layer>, readonly alpha: number }
- function Overpaint(layers: ReadonlyArray<Overpaint.Layer>, alpha: number): Overpaint {
- return { layers, alpha }
- }
- namespace Overpaint {
- export type Layer = { readonly loci: StructureElement.Loci, readonly color: Color, readonly clear: boolean }
- export const Empty: Overpaint = { layers: [], alpha: 1 }
- export function areEqual(oA: Overpaint, oB: Overpaint) {
- if (oA.layers.length === 0 && oB.layers.length === 0) return true
- if (oA.layers.length !== oB.layers.length) return false
- if (oA.alpha !== oB.alpha) return false
- for (let i = 0, il = oA.layers.length; i < il; ++i) {
- if (oA.layers[i].clear !== oB.layers[i].clear) return false
- if (oA.layers[i].color !== oB.layers[i].color) return false
- if (!Loci.areEqual(oA.layers[i].loci, oB.layers[i].loci)) return false
- }
- return true
- }
- export function isEmpty(overpaint: Overpaint) {
- return overpaint.layers.length === 0
- }
- export function remap(overpaint: Overpaint, structure: Structure) {
- const layers: Overpaint.Layer[] = []
- for (const layer of overpaint.layers) {
- let { loci, color, clear } = layer
- loci = StructureElement.Loci.remap(loci, structure)
- if (!StructureElement.Loci.isEmpty(loci)) {
- layers.push({ loci, color, clear })
- }
- }
- return { layers, alpha: overpaint.alpha }
- }
- export function merge(overpaint: Overpaint): Overpaint {
- if (isEmpty(overpaint)) return overpaint
- const { structure } = overpaint.layers[0].loci
- const map = new Map<Color | -1, StructureElement.Loci>()
- let shadowed = StructureElement.Loci.none(structure)
- for (let i = 0, il = overpaint.layers.length; i < il; ++i) {
- let { loci, color, clear } = overpaint.layers[il - i - 1] // process from end
- loci = StructureElement.Loci.subtract(loci, shadowed)
- shadowed = StructureElement.Loci.union(loci, shadowed)
- if (!StructureElement.Loci.isEmpty(loci)) {
- const colorOrClear = clear ? -1 : color
- if (map.has(colorOrClear)) {
- loci = StructureElement.Loci.union(loci, map.get(colorOrClear)!)
- }
- map.set(colorOrClear, loci)
- }
- }
- const layers: Overpaint.Layer[] = []
- map.forEach((loci, colorOrClear) => {
- const clear = colorOrClear === -1
- const color = colorOrClear === -1 ? Color(0) : colorOrClear
- layers.push({ loci, color, clear })
- })
- return { layers, alpha: overpaint.alpha }
- }
- export function filter(overpaint: Overpaint, filter: Structure): Overpaint {
- if (isEmpty(overpaint)) return overpaint
- const { structure } = overpaint.layers[0].loci
- const layers: Overpaint.Layer[] = []
- for (const layer of overpaint.layers) {
- let { loci, color, clear } = layer
- // filter by first map to the `filter` structure and
- // then map back to the original structure of the overpaint loci
- const filtered = StructureElement.Loci.remap(loci, filter)
- loci = StructureElement.Loci.remap(filtered, structure)
- if (!StructureElement.Loci.isEmpty(loci)) {
- layers.push({ loci, color, clear })
- }
- }
- return { layers, alpha: overpaint.alpha }
- }
- export type ScriptLayer = { script: Script, color: Color, clear: boolean }
- export function ofScript(scriptLayers: ScriptLayer[], alpha: number, structure: Structure): Overpaint {
- const layers: Overpaint.Layer[] = []
- for (let i = 0, il = scriptLayers.length; i < il; ++i) {
- const { script, color, clear } = scriptLayers[i]
- const loci = Script.toLoci(script, structure)
- if (!StructureElement.Loci.isEmpty(loci)) {
- layers.push({ loci, color, clear })
- }
- }
- return { layers, alpha }
- }
- export type BundleLayer = { bundle: StructureElement.Bundle, color: Color, clear: boolean }
- export function ofBundle(bundleLayers: BundleLayer[], alpha: number, structure: Structure): Overpaint {
- const layers: Overpaint.Layer[] = []
- for (let i = 0, il = bundleLayers.length; i < il; ++i) {
- const { bundle, color, clear } = bundleLayers[i]
- const loci = StructureElement.Bundle.toLoci(bundle, structure.root)
- layers.push({ loci, color, clear })
- }
- return { layers, alpha }
- }
- export function toBundle(overpaint: Overpaint, alpha: number) {
- const layers: BundleLayer[] = []
- for (let i = 0, il = overpaint.layers.length; i < il; ++i) {
- let { loci, color, clear } = overpaint.layers[i]
- const bundle = StructureElement.Bundle.fromLoci(loci)
- layers.push({ bundle, color, clear })
- }
- return { layers, alpha }
- }
- }
|