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

wip, repr

parent 78fdc0d8
Branches
Tags
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 }
if (structureVisualCtor) {
structureVisual = structureVisualCtor()
await structureVisual.create(ctx, structure, _props)
}
} else {
if (_structure.hashCode === structure.hashCode) {
await update(_props)
} else {
_groups = StructureSymmetry.getTransformGroups(structure);
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 group = groups[i]; unusedVisuals.forEach(visual => visual.destroy())
const visual = visualCtor()
groupVisuals.push({ visual, group }) if (structureVisual) {
await visual.create(ctx, group, props) if (!await structureVisual.update(ctx, _props)) {
renderObjects.push(...visual.renderObjects) await structureVisual.create(ctx, _structure, _props)
}
}
} }
}
_structure = structure
}); });
}, }
update(props: P) {
return Task.create('StructureRepresentation.update', async ctx => { function update(props: P) {
renderObjects.length = 0 // clear return Task.create('Updating StructureRepresentation', async ctx => {
_props = Object.assign({}, DefaultStructureProps, _props, props)
for (let i = 0, il = groupVisuals.length; i < il; ++i) {
if(ctx.shouldUpdate) await ctx.update({ unitsVisuals.forEach(async ({ visual, group }) => {
message: 'Updating structure unit visuals...', if (!await visual.update(ctx, _props)) {
current: i, await visual.create(ctx, group, _props)
max: il }
}) })
const groupVisual = groupVisuals[i]
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)
} }
}) })
},
getLoci(pickingId: PickingId) {
for (let i = 0, il = groupVisuals.length; i < il; ++i) {
const loc = groupVisuals[i].visual.getLoci(pickingId)
if (!isEmptyLoci(loc)) return loc
} }
return EmptyLoci
}, function getLoci(pickingId: PickingId) {
mark(loci: Loci, action: MarkerAction) { let loci: Loci = EmptyLoci
for (let i = 0, il = groupVisuals.length; i < il; ++i) { unitsVisuals.forEach(({ visual }) => {
groupVisuals[i].visual.mark(loci, action) 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
},
create,
update,
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
return { function create(volumeData: VolumeData, props: P = {} as P) {
renderObjects,
create(volumeData: VolumeData, props: P = {} as P) {
return Task.create('VolumeRepresentation.create', async ctx => { return Task.create('VolumeRepresentation.create', async ctx => {
const visual = visualCtor() _volumeData = volumeData
await visual.create(ctx, volumeData, props) const visual = visualCtor(_volumeData)
await visual.create(ctx, _volumeData, props)
renderObjects.push(...visual.renderObjects) renderObjects.push(...visual.renderObjects)
}); });
}, }
update(props: P) {
function update(props: P) {
return Task.create('VolumeRepresentation.update', async ctx => {}) return Task.create('VolumeRepresentation.update', async ctx => {})
}, }
return {
renderObjects,
create,
update,
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.
Please register or to comment