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

overpaint improvements, merge and filter

parent 7566cc89
No related branches found
No related tags found
No related merge requests found
......@@ -76,13 +76,13 @@ namespace Loci {
return false
}
export function isEmpty(loci: Loci) {
export function isEmpty(loci: Loci): boolean {
if (isEveryLoci(loci)) return false
if (isEmptyLoci(loci)) return true
if (isDataLoci(loci)) return isDataLociEmpty(loci)
if (Structure.isLoci(loci)) return Structure.isLociEmpty(loci)
if (StructureElement.Loci.is(loci)) StructureElement.Loci.isEmpty(loci)
if (Link.isLoci(loci)) Link.isLociEmpty(loci)
if (StructureElement.Loci.is(loci)) return StructureElement.Loci.isEmpty(loci)
if (Link.isLoci(loci)) return Link.isLociEmpty(loci)
if (Shape.isLoci(loci)) return Shape.isLociEmpty(loci)
if (ShapeGroup.isLoci(loci)) return ShapeGroup.isLociEmpty(loci)
return false
......
......@@ -10,6 +10,7 @@ import { StateSelection, StateObjectCell, StateTransform, StateBuilder } from '.
import { Structure, StructureElement } from '../../mol-model/structure';
import { PluginContext } from '../context';
import { Color } from '../../mol-util/color';
import { Overpaint } from '../../mol-theme/overpaint';
type OverpaintEachReprCallback = (update: StateBuilder.Root, repr: StateObjectCell<PluginStateObject.Molecule.Structure.Representation3D, StateTransform<typeof StateTransforms.Representation.StructureRepresentation3D>>, overpaint?: StateObjectCell<any, StateTransform<typeof StateTransforms.Representation.OverpaintStructureRepresentation3DFromBundle>>) => void
const OverpaintManagerTag = 'overpaint-controls'
......@@ -29,12 +30,9 @@ export class StructureOverpaintHelper {
}
async set(color: Color | -1, lociGetter: (structure: Structure) => StructureElement.Loci, types?: string[]) {
await this.eachRepr((update, repr, overpaint) => {
await this.eachRepr((update, repr, overpaintCell) => {
if (types && !types.includes(repr.params!.values.type.name)) return
// TODO merge overpaint layers, delete shadowed ones
// TODO filter overpaint layers for given structure
const structure = repr.obj!.data.source.data
// always use the root structure to get the loci so the overpaint
// stays applicable as long as the root structure does not change
......@@ -47,11 +45,14 @@ export class StructureOverpaintHelper {
clear: color === -1
}
if (overpaint) {
update.to(overpaint).update({ layers: [ ...overpaint.params!.values.layers, layer ], alpha: 1 })
if (overpaintCell) {
const bundleLayers = [ ...overpaintCell.params!.values.layers, layer ]
const filtered = getFilteredBundle(bundleLayers, structure)
update.to(overpaintCell).update(Overpaint.toBundle(filtered, 1))
} else {
const filtered = getFilteredBundle([ layer ], structure)
update.to(repr.transform.ref)
.apply(StateTransforms.Representation.OverpaintStructureRepresentation3DFromBundle, { layers: [ layer ], alpha: 1 }, { tags: OverpaintManagerTag });
.apply(StateTransforms.Representation.OverpaintStructureRepresentation3DFromBundle, Overpaint.toBundle(filtered, 1), { tags: OverpaintManagerTag });
}
})
}
......@@ -59,4 +60,11 @@ export class StructureOverpaintHelper {
constructor(private plugin: PluginContext) {
}
}
/** filter overpaint layers for given structure */
function getFilteredBundle(layers: Overpaint.BundleLayer[], structure: Structure) {
const overpaint = Overpaint.ofBundle(layers, 1, structure.root)
const merged = Overpaint.merge(overpaint)
return Overpaint.filter(merged, structure)
}
\ No newline at end of file
......@@ -184,8 +184,10 @@ export function UnitsRepresentation<P extends UnitsParams>(label: string, ctx: R
if (pickable !== undefined) visuals.forEach(({ visual }) => visual.setPickable(pickable))
if (overpaint !== undefined) {
// Remap loci from equivalent structure to the current `_structure`
const remappedOverpaint = Overpaint.remap(overpaint, _structure)
visuals.forEach(({ visual }) => visual.setOverpaint(remappedOverpaint))
if (_structure) {
const remappedOverpaint = Overpaint.remap(overpaint, _structure)
visuals.forEach(({ visual }) => visual.setOverpaint(remappedOverpaint))
}
}
if (transparency !== undefined) visuals.forEach(({ visual }) => visual.setTransparency(transparency))
if (transform !== undefined) visuals.forEach(({ visual }) => visual.setTransform(transform))
......
......@@ -11,10 +11,14 @@ import { Script } from '../mol-script/script';
export { Overpaint }
type Overpaint = { layers: ReadonlyArray<Overpaint.Layer>, readonly alpha: number }
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: Loci, readonly color: Color, readonly clear: boolean }
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) {
......@@ -29,25 +33,80 @@ namespace Overpaint {
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) {
const { loci, color, clear } = layer
layers.push({ loci: Loci.remap(loci, structure), color, clear })
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 ofScript(scriptLayers: { script: Script, color: Color, clear: boolean }[], alpha: number, structure: Structure): Overpaint {
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]
layers.push({ loci: Script.toLoci(script, structure), color, clear })
const loci = Script.toLoci(script, structure)
if (!StructureElement.Loci.isEmpty(loci)) {
layers.push({ loci, color, clear })
}
}
return { layers, alpha }
}
export function ofBundle(bundleLayers: { bundle: StructureElement.Bundle, color: Color, clear: boolean }[], alpha: number, structure: Structure): Overpaint {
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]
......@@ -56,4 +115,14 @@ namespace Overpaint {
}
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 }
}
}
\ 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