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

wip, repr

parent 78fdc0d8
No related branches found
No related tags found
No related merge requests found
...@@ -4,7 +4,7 @@ ...@@ -4,7 +4,7 @@
* @author Alexander Rose <alexander.rose@weirdbyte.de> * @author Alexander Rose <alexander.rose@weirdbyte.de>
*/ */
import { Task } from 'mol-task' import { Task, RuntimeContext } from 'mol-task'
import { RenderObject } from 'mol-gl/render-object' import { RenderObject } from 'mol-gl/render-object'
import { PickingId } from '../util/picking'; import { PickingId } from '../util/picking';
import { Loci } from 'mol-model/loci'; import { Loci } from 'mol-model/loci';
...@@ -13,9 +13,19 @@ import { MarkerAction } from '../util/marker-data'; ...@@ -13,9 +13,19 @@ import { MarkerAction } from '../util/marker-data';
export interface RepresentationProps {} export interface RepresentationProps {}
export interface Representation<D, P extends RepresentationProps = {}> { export interface Representation<D, P extends RepresentationProps = {}> {
renderObjects: ReadonlyArray<RenderObject> readonly renderObjects: ReadonlyArray<RenderObject>
create: (data: D, props?: P) => Task<void> create: (data: D, props?: P) => Task<void>
update: (props: P) => Task<void> update: (props: P) => Task<void>
getLoci: (pickingId: PickingId) => Loci getLoci: (pickingId: PickingId) => Loci
mark: (loci: Loci, action: MarkerAction) => void mark: (loci: Loci, action: MarkerAction) => void
destroy: () => void
}
export interface Visual<D, P extends RepresentationProps = {}> {
readonly renderObjects: ReadonlyArray<RenderObject>
create: (ctx: RuntimeContext, data: D, props: P) => Promise<void>
update: (ctx: RuntimeContext, props: P) => Promise<boolean>
getLoci: (pickingId: PickingId) => Loci
mark: (loci: Loci, action: MarkerAction) => void
destroy: () => void
} }
\ No newline at end of file
...@@ -78,7 +78,7 @@ export const DefaultBondProps = { ...@@ -78,7 +78,7 @@ export const DefaultBondProps = {
} }
export type BondProps = Partial<typeof DefaultBondProps> export type BondProps = Partial<typeof DefaultBondProps>
export default function IntraUnitBonds(): UnitsVisual<BondProps> { export default function IntraUnitBondVisual(): UnitsVisual<BondProps> {
const renderObjects: RenderObject[] = [] const renderObjects: RenderObject[] = []
let cylinders: MeshRenderObject let cylinders: MeshRenderObject
let currentProps: typeof DefaultBondProps let currentProps: typeof DefaultBondProps
...@@ -203,6 +203,9 @@ export default function IntraUnitBonds(): UnitsVisual<BondProps> { ...@@ -203,6 +203,9 @@ export default function IntraUnitBonds(): UnitsVisual<BondProps> {
if (changed) { if (changed) {
ValueCell.update(tMarker, tMarker.ref.value) ValueCell.update(tMarker, tMarker.ref.value)
} }
},
destroy() {
// TODO
} }
} }
} }
...@@ -6,29 +6,19 @@ ...@@ -6,29 +6,19 @@
*/ */
import { Structure, StructureSymmetry, Unit } from 'mol-model/structure'; import { Structure, StructureSymmetry, Unit } from 'mol-model/structure';
import { Task, RuntimeContext } from 'mol-task' import { Task } from 'mol-task'
import { RenderObject } from 'mol-gl/render-object'; import { RenderObject } from 'mol-gl/render-object';
import { Representation, RepresentationProps } from '..'; import { Representation, RepresentationProps, Visual } from '..';
import { ColorTheme } from '../../theme'; import { ColorTheme } from '../../theme';
import { PickingId } from '../../util/picking'; import { PickingId } from '../../util/picking';
import { Loci, EmptyLoci, isEmptyLoci } from 'mol-model/loci'; import { Loci, EmptyLoci, isEmptyLoci } from 'mol-model/loci';
import { MarkerAction } from '../../util/marker-data'; import { MarkerAction } from '../../util/marker-data';
export interface UnitsVisual<P> { export interface UnitsVisual<P extends RepresentationProps = {}> extends Visual<Unit.SymmetryGroup, P> { }
readonly renderObjects: ReadonlyArray<RenderObject> export interface StructureVisual<P extends RepresentationProps = {}> extends Visual<Structure, P> { }
create: (ctx: RuntimeContext, group: Unit.SymmetryGroup, props: P) => Promise<void>
update: (ctx: RuntimeContext, props: P) => Promise<boolean>
getLoci: (pickingId: PickingId) => Loci
mark: (loci: Loci, action: MarkerAction) => void
}
export interface StructureRepresentation<P extends RepresentationProps = {}> extends Representation<Structure, P> { } export interface StructureRepresentation<P extends RepresentationProps = {}> extends Representation<Structure, P> { }
interface GroupVisual<T> {
readonly visual: UnitsVisual<T>
readonly group: Unit.SymmetryGroup
}
export const DefaultStructureProps = { export const DefaultStructureProps = {
colorTheme: { name: 'instance-index' } as ColorTheme, colorTheme: { name: 'instance-index' } as ColorTheme,
alpha: 1, alpha: 1,
...@@ -39,68 +29,123 @@ export const DefaultStructureProps = { ...@@ -39,68 +29,123 @@ export const DefaultStructureProps = {
} }
export type StructureProps = Partial<typeof DefaultStructureProps> export type StructureProps = Partial<typeof DefaultStructureProps>
export function StructureRepresentation<P extends StructureProps>(visualCtor: () => UnitsVisual<P>): StructureRepresentation<P> { export function StructureRepresentation<P extends StructureProps>(unitsVisualCtor: () => UnitsVisual<P>, structureVisualCtor?: () => StructureVisual<P>): StructureRepresentation<P> {
const renderObjects: RenderObject[] = [] let unitsVisuals = new Map<number, { group: Unit.SymmetryGroup, visual: UnitsVisual<P> }>()
const groupVisuals: GroupVisual<P>[] = [] let structureVisual: StructureVisual<P> | undefined
// let currentProps: typeof DefaultStructureProps
return { let _props: Required<P>
renderObjects, let _structure: Structure
create(structure: Structure, props: P = {} as P) { let _groups: ReadonlyArray<Unit.SymmetryGroup>
// currentProps = Object.assign({}, DefaultStructureProps, props)
function create(structure: Structure, props: P = {} as P) {
return Task.create('StructureRepresentation.create', async ctx => { _props = Object.assign({}, DefaultStructureProps, _props, props)
// const { query } = currentProps
// const qs = await query(structure).runAsChild(ctx) return Task.create('Creating StructureRepresentation', async ctx => {
// const subStructure = Selection.unionStructure(qs) if (!_structure) {
_groups = StructureSymmetry.getTransformGroups(structure);
const groups = StructureSymmetry.getTransformGroups(structure); for (let i = 0; i < _groups.length; i++) {
for (let i = 0; i < groups.length; i++) { const group = _groups[i];
if(ctx.shouldUpdate) await ctx.update({ const visual = unitsVisualCtor()
message: 'Building structure unit visuals...', await visual.create(ctx, group, _props)
current: i, unitsVisuals.set(group.hashCode, { visual, group })
max: groups.length
})
const group = groups[i];
const visual = visualCtor()
groupVisuals.push({ visual, group })
await visual.create(ctx, group, props)
renderObjects.push(...visual.renderObjects)
} }
});
}, if (structureVisualCtor) {
update(props: P) { structureVisual = structureVisualCtor()
return Task.create('StructureRepresentation.update', async ctx => { await structureVisual.create(ctx, structure, _props)
renderObjects.length = 0 // clear }
} else {
for (let i = 0, il = groupVisuals.length; i < il; ++i) { if (_structure.hashCode === structure.hashCode) {
if(ctx.shouldUpdate) await ctx.update({ await update(_props)
message: 'Updating structure unit visuals...', } else {
current: i, _groups = StructureSymmetry.getTransformGroups(structure);
max: il const newGroups: Unit.SymmetryGroup[] = []
const oldUnitsVisuals = unitsVisuals
unitsVisuals = new Map()
for (let i = 0; i < _groups.length; i++) {
const group = _groups[i];
const visualGroup = oldUnitsVisuals.get(group.hashCode)
if (visualGroup) {
const { visual, group } = visualGroup
if (!await visual.update(ctx, _props)) {
await visual.create(ctx, group, _props)
}
oldUnitsVisuals.delete(group.hashCode)
} else {
newGroups.push(group)
const visual = unitsVisualCtor()
await visual.create(ctx, group, _props)
unitsVisuals.set(group.hashCode, { visual, group })
}
}
// for new groups, reuse leftover visuals
const unusedVisuals: UnitsVisual<P>[] = []
oldUnitsVisuals.forEach(({ visual }) => unusedVisuals.push(visual))
newGroups.forEach(async group => {
const visual = unusedVisuals.pop() || unitsVisualCtor()
await visual.create(ctx, group, _props)
unitsVisuals.set(group.hashCode, { visual, group })
}) })
const groupVisual = groupVisuals[i] unusedVisuals.forEach(visual => visual.destroy())
const { visual, group } = groupVisual
if (!await visual.update(ctx, props)) { if (structureVisual) {
console.log('update failed, need to rebuild') if (!await structureVisual.update(ctx, _props)) {
visual.create(ctx, group, props) await structureVisual.create(ctx, _structure, _props)
}
} }
renderObjects.push(...visual.renderObjects) }
}
_structure = structure
});
}
function update(props: P) {
return Task.create('Updating StructureRepresentation', async ctx => {
_props = Object.assign({}, DefaultStructureProps, _props, props)
unitsVisuals.forEach(async ({ visual, group }) => {
if (!await visual.update(ctx, _props)) {
await visual.create(ctx, group, _props)
} }
}) })
},
getLoci(pickingId: PickingId) { if (structureVisual) {
for (let i = 0, il = groupVisuals.length; i < il; ++i) { if (!await structureVisual.update(ctx, _props)) {
const loc = groupVisuals[i].visual.getLoci(pickingId) await structureVisual.create(ctx, _structure, _props)
if (!isEmptyLoci(loc)) return loc }
} }
return EmptyLoci })
}
function getLoci(pickingId: PickingId) {
let loci: Loci = EmptyLoci
unitsVisuals.forEach(({ visual }) => {
const _loci = visual.getLoci(pickingId)
if (!isEmptyLoci(_loci)) loci = _loci
})
return loci
}
function mark(loci: Loci, action: MarkerAction) {
unitsVisuals.forEach(({ visual }) => visual.mark(loci, action))
}
function destroy() {
unitsVisuals.forEach(({ visual }) => visual.destroy())
unitsVisuals.clear()
}
return {
get renderObjects() {
const renderObjects: RenderObject[] = []
unitsVisuals.forEach(({ visual }) => renderObjects.push(...visual.renderObjects))
return renderObjects
}, },
mark(loci: Loci, action: MarkerAction) { create,
for (let i = 0, il = groupVisuals.length; i < il; ++i) { update,
groupVisuals[i].visual.mark(loci, action) getLoci,
} mark,
} destroy
} }
} }
\ No newline at end of file
...@@ -47,7 +47,7 @@ export function createPointVertices(unit: Unit) { ...@@ -47,7 +47,7 @@ export function createPointVertices(unit: Unit) {
return vertices return vertices
} }
export default function PointUnitsRepresentation(): UnitsVisual<PointProps> { export default function PointVisual(): UnitsVisual<PointProps> {
const renderObjects: RenderObject[] = [] const renderObjects: RenderObject[] = []
let points: PointRenderObject let points: PointRenderObject
let currentProps = DefaultPointProps let currentProps = DefaultPointProps
...@@ -164,6 +164,9 @@ export default function PointUnitsRepresentation(): UnitsVisual<PointProps> { ...@@ -164,6 +164,9 @@ export default function PointUnitsRepresentation(): UnitsVisual<PointProps> {
}, },
mark(loci: Loci, action: MarkerAction) { mark(loci: Loci, action: MarkerAction) {
markElement(points.values.tMarker, currentGroup, loci, action) markElement(points.values.tMarker, currentGroup, loci, action)
},
destroy() {
// TODO
} }
} }
} }
...@@ -9,7 +9,7 @@ import { ValueCell } from 'mol-util/value-cell' ...@@ -9,7 +9,7 @@ import { ValueCell } from 'mol-util/value-cell'
import { RenderObject, createMeshRenderObject, MeshRenderObject } from 'mol-gl/render-object' import { RenderObject, createMeshRenderObject, MeshRenderObject } from 'mol-gl/render-object'
import { Unit, Element, Queries } from 'mol-model/structure'; import { Unit, Element, Queries } from 'mol-model/structure';
import { UnitsVisual, DefaultStructureProps } from './index'; import { DefaultStructureProps, UnitsVisual } from './index';
import { RuntimeContext } from 'mol-task' import { RuntimeContext } from 'mol-task'
import { createTransforms, createColors, createSphereMesh, markElement } from './utils'; import { createTransforms, createColors, createSphereMesh, markElement } from './utils';
import VertexMap from '../../shape/vertex-map'; import VertexMap from '../../shape/vertex-map';
...@@ -44,7 +44,7 @@ export const DefaultSpacefillProps = { ...@@ -44,7 +44,7 @@ export const DefaultSpacefillProps = {
} }
export type SpacefillProps = Partial<typeof DefaultSpacefillProps> export type SpacefillProps = Partial<typeof DefaultSpacefillProps>
export default function SpacefillUnitsRepresentation(): UnitsVisual<SpacefillProps> { export default function SpacefillVisual(): UnitsVisual<SpacefillProps> {
const renderObjects: RenderObject[] = [] const renderObjects: RenderObject[] = []
let spheres: MeshRenderObject let spheres: MeshRenderObject
let currentProps: typeof DefaultSpacefillProps let currentProps: typeof DefaultSpacefillProps
...@@ -152,6 +152,9 @@ export default function SpacefillUnitsRepresentation(): UnitsVisual<SpacefillPro ...@@ -152,6 +152,9 @@ export default function SpacefillUnitsRepresentation(): UnitsVisual<SpacefillPro
}, },
mark(loci: Loci, action: MarkerAction) { mark(loci: Loci, action: MarkerAction) {
markElement(spheres.values.tMarker, currentGroup, loci, action) markElement(spheres.values.tMarker, currentGroup, loci, action)
},
destroy() {
// TODO
} }
} }
} }
...@@ -4,45 +4,48 @@ ...@@ -4,45 +4,48 @@
* @author Alexander Rose <alexander.rose@weirdbyte.de> * @author Alexander Rose <alexander.rose@weirdbyte.de>
*/ */
import { Task, RuntimeContext } from 'mol-task' import { Task } from 'mol-task'
import { RenderObject } from 'mol-gl/render-object'; import { RenderObject } from 'mol-gl/render-object';
import { RepresentationProps, Representation } from '..'; import { RepresentationProps, Representation, Visual } from '..';
import { VolumeData } from 'mol-model/volume'; import { VolumeData } from 'mol-model/volume';
import { PickingId } from '../../util/picking'; import { PickingId } from '../../util/picking';
import { Loci, EmptyLoci } from 'mol-model/loci'; import { Loci, EmptyLoci } from 'mol-model/loci';
import { MarkerAction } from '../../util/marker-data'; import { MarkerAction } from '../../util/marker-data';
export interface VolumeVisual<P> { export interface VolumeVisual<P extends RepresentationProps = {}> extends Visual<VolumeData, P> { }
readonly renderObjects: ReadonlyArray<RenderObject>
create: (ctx: RuntimeContext, volumeData: VolumeData, props: P) => Promise<void>
update: (ctx: RuntimeContext, props: P) => Promise<boolean>
getLoci: (pickingId: PickingId) => Loci
mark: (loci: Loci, action: MarkerAction) => void
}
export interface VolumeRepresentation<P extends RepresentationProps = {}> extends Representation<VolumeData, P> { } export interface VolumeRepresentation<P extends RepresentationProps = {}> extends Representation<VolumeData, P> { }
export function VolumeRepresentation<P>(visualCtor: () => VolumeVisual<P>): VolumeRepresentation<P> { export function VolumeRepresentation<P>(visualCtor: (volumeData: VolumeData) => VolumeVisual<P>): VolumeRepresentation<P> {
const renderObjects: RenderObject[] = [] const renderObjects: RenderObject[] = []
let _volumeData: VolumeData
function create(volumeData: VolumeData, props: P = {} as P) {
return Task.create('VolumeRepresentation.create', async ctx => {
_volumeData = volumeData
const visual = visualCtor(_volumeData)
await visual.create(ctx, _volumeData, props)
renderObjects.push(...visual.renderObjects)
});
}
function update(props: P) {
return Task.create('VolumeRepresentation.update', async ctx => {})
}
return { return {
renderObjects, renderObjects,
create(volumeData: VolumeData, props: P = {} as P) { create,
return Task.create('VolumeRepresentation.create', async ctx => { update,
const visual = visualCtor()
await visual.create(ctx, volumeData, props)
renderObjects.push(...visual.renderObjects)
});
},
update(props: P) {
return Task.create('VolumeRepresentation.update', async ctx => {})
},
getLoci(pickingId: PickingId) { getLoci(pickingId: PickingId) {
// TODO // TODO
return EmptyLoci return EmptyLoci
}, },
mark(loci: Loci, action: MarkerAction) { mark(loci: Loci, action: MarkerAction) {
// TODO // TODO
},
destroy() {
// TODO
} }
} }
} }
\ No newline at end of file
...@@ -50,7 +50,7 @@ export const DefaultSurfaceProps = { ...@@ -50,7 +50,7 @@ export const DefaultSurfaceProps = {
} }
export type SurfaceProps = Partial<typeof DefaultSurfaceProps> export type SurfaceProps = Partial<typeof DefaultSurfaceProps>
export default function Surface(): VolumeVisual<SurfaceProps> { export default function SurfaceVisual(): VolumeVisual<SurfaceProps> {
const renderObjects: RenderObject[] = [] const renderObjects: RenderObject[] = []
let surface: MeshRenderObject let surface: MeshRenderObject
let curProps = DefaultSurfaceProps let curProps = DefaultSurfaceProps
...@@ -109,6 +109,9 @@ export default function Surface(): VolumeVisual<SurfaceProps> { ...@@ -109,6 +109,9 @@ export default function Surface(): VolumeVisual<SurfaceProps> {
}, },
mark(loci: Loci, action: MarkerAction) { mark(loci: Loci, action: MarkerAction) {
// TODO // TODO
},
destroy() {
// TODO
} }
} }
} }
...@@ -60,7 +60,7 @@ namespace StructureSymmetry { ...@@ -60,7 +60,7 @@ namespace StructureSymmetry {
return hash2(u.invariantId, SortedArray.hashCode(u.elements)); return hash2(u.invariantId, SortedArray.hashCode(u.elements));
} }
function areUnitsEquivalent(a: Unit, b: Unit) { export function areUnitsEquivalent(a: Unit, b: Unit) {
return a.invariantId === b.invariantId && a.model.id === b.model.id && SortedArray.areEqual(a.elements, b.elements); return a.invariantId === b.invariantId && a.model.id === b.model.id && SortedArray.areEqual(a.elements, b.elements);
} }
...@@ -75,7 +75,11 @@ namespace StructureSymmetry { ...@@ -75,7 +75,11 @@ namespace StructureSymmetry {
const ret: Unit.SymmetryGroup[] = []; const ret: Unit.SymmetryGroup[] = [];
for (const eqUnits of groups.groups) { for (const eqUnits of groups.groups) {
const first = s.unitMap.get(eqUnits[0]); const first = s.unitMap.get(eqUnits[0]);
ret.push({ elements: first.elements, units: eqUnits.map(id => s.unitMap.get(id)) }); ret.push({
elements: first.elements,
units: eqUnits.map(id => s.unitMap.get(id)),
hashCode: hashUnit(first)
});
} }
return ret; return ret;
......
...@@ -35,7 +35,11 @@ namespace Unit { ...@@ -35,7 +35,11 @@ namespace Unit {
} }
/** A group of units that differ only by symmetry operators. */ /** A group of units that differ only by symmetry operators. */
export type SymmetryGroup = { readonly elements: Element.Set, readonly units: ReadonlyArray<Unit> } export type SymmetryGroup = {
readonly elements: Element.Set,
readonly units: ReadonlyArray<Unit>
readonly hashCode: number
}
/** Find index of unit with given id, returns -1 if not found */ /** Find index of unit with given id, returns -1 if not found */
export function findUnitById(id: number, units: ReadonlyArray<Unit>) { export function findUnitById(id: number, units: ReadonlyArray<Unit>) {
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment