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

Merge branch 'master' into graphics

parents 3c345cc6 8214f0f9
No related branches found
No related tags found
No related merge requests found
/** /**
* Copyright (c) 2018 mol* contributors, licensed under MIT, See LICENSE file for more info. * Copyright (c) 2018-2019 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>
*/ */
import { StructureElement } from './structure' import { StructureElement } from './structure'
import { Link } from './structure/structure/unit/links' import { Link } from './structure/structure/unit/links'
import { Shape } from './shape/shape'; import { ShapeGroup } from './shape/shape';
/** A null value Location */ /** A null value Location */
export const NullLocation = { kind: 'null-location' as 'null-location' } export const NullLocation = { kind: 'null-location' as 'null-location' }
...@@ -15,4 +15,4 @@ export function isNullLocation(x: any): x is NullLocation { ...@@ -15,4 +15,4 @@ export function isNullLocation(x: any): x is NullLocation {
return !!x && x.kind === 'null-location'; return !!x && x.kind === 'null-location';
} }
export type Location = StructureElement | Link.Location | Shape.Location | NullLocation export type Location = StructureElement | Link.Location | ShapeGroup.Location | NullLocation
\ No newline at end of file \ No newline at end of file
/** /**
* Copyright (c) 2018 mol* contributors, licensed under MIT, See LICENSE file for more info. * Copyright (c) 2018-2019 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>
*/ */
import { StructureElement } from './structure' import { StructureElement } from './structure'
import { Link } from './structure/structure/unit/links' import { Link } from './structure/structure/unit/links'
import { Shape } from './shape'; import { Shape, ShapeGroup } from './shape';
import { Sphere3D } from 'mol-math/geometry'; import { Sphere3D } from 'mol-math/geometry';
import { CentroidHelper } from 'mol-math/geometry/centroid-helper'; import { CentroidHelper } from 'mol-math/geometry/centroid-helper';
import { Vec3 } from 'mol-math/linear-algebra'; import { Vec3 } from 'mol-math/linear-algebra';
...@@ -46,7 +46,7 @@ export function createDataLoci(data: any, tag: string, indices: OrderedSet<numbe ...@@ -46,7 +46,7 @@ export function createDataLoci(data: any, tag: string, indices: OrderedSet<numbe
export { Loci } export { Loci }
type Loci = StructureElement.Loci | Structure.Loci | Link.Loci | EveryLoci | EmptyLoci | DataLoci | Shape.Loci type Loci = StructureElement.Loci | Structure.Loci | Link.Loci | EveryLoci | EmptyLoci | DataLoci | Shape.Loci | ShapeGroup.Loci
namespace Loci { namespace Loci {
export function areEqual(lociA: Loci, lociB: Loci) { export function areEqual(lociA: Loci, lociB: Loci) {
...@@ -67,6 +67,9 @@ namespace Loci { ...@@ -67,6 +67,9 @@ namespace Loci {
if (Shape.isLoci(lociA) && Shape.isLoci(lociB)) { if (Shape.isLoci(lociA) && Shape.isLoci(lociB)) {
return Shape.areLociEqual(lociA, lociB) return Shape.areLociEqual(lociA, lociB)
} }
if (ShapeGroup.isLoci(lociA) && ShapeGroup.isLoci(lociB)) {
return ShapeGroup.areLociEqual(lociA, lociB)
}
return false return false
} }
...@@ -96,6 +99,9 @@ namespace Loci { ...@@ -96,6 +99,9 @@ namespace Loci {
e.aUnit.conformation.position(e.bUnit.elements[e.bIndex], tempPos); e.aUnit.conformation.position(e.bUnit.elements[e.bIndex], tempPos);
sphereHelper.radiusStep(tempPos); sphereHelper.radiusStep(tempPos);
} }
} else if (loci.kind === 'shape-loci') {
// TODO
return void 0;
} else if (loci.kind === 'group-loci') { } else if (loci.kind === 'group-loci') {
// TODO // TODO
return void 0; return void 0;
......
/** /**
* Copyright (c) 2018 mol* contributors, licensed under MIT, See LICENSE file for more info. * Copyright (c) 2018-2019 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>
*/ */
...@@ -43,6 +43,13 @@ export namespace Shape { ...@@ -43,6 +43,13 @@ export namespace Shape {
} }
} }
export interface Loci { readonly kind: 'shape-loci', readonly shape: Shape }
export function Loci(shape: Shape): Loci { return { kind: 'shape-loci', shape } }
export function isLoci(x: any): x is Loci { return !!x && x.kind === 'shape-loci' }
export function areLociEqual(a: Loci, b: Loci) { return a.shape === b.shape }
}
export namespace ShapeGroup {
export interface Location { export interface Location {
readonly kind: 'group-location' readonly kind: 'group-location'
shape: Shape shape: Shape
......
...@@ -22,6 +22,7 @@ import { VolumeServerHeader, VolumeServerInfo } from './model'; ...@@ -22,6 +22,7 @@ import { VolumeServerHeader, VolumeServerInfo } from './model';
import { ButtonsType } from 'mol-util/input/input-observer'; import { ButtonsType } from 'mol-util/input/input-observer';
import { PluginCommands } from 'mol-plugin/command'; import { PluginCommands } from 'mol-plugin/command';
import { StateSelection } from 'mol-state'; import { StateSelection } from 'mol-state';
import { Representation } from 'mol-repr/representation';
export class VolumeStreaming extends PluginStateObject.CreateBehavior<VolumeStreaming.Behavior>({ name: 'Volume Streaming' }) { } export class VolumeStreaming extends PluginStateObject.CreateBehavior<VolumeStreaming.Behavior>({ name: 'Volume Streaming' }) { }
...@@ -172,7 +173,21 @@ export namespace VolumeStreaming { ...@@ -172,7 +173,21 @@ export namespace VolumeStreaming {
} }
register(ref: string): void { register(ref: string): void {
// this.ref = ref; let lastLoci: Representation.Loci = Representation.Loci.Empty;
this.subscribeObservable(this.plugin.events.state.object.removed, o => {
if (!PluginStateObject.Molecule.Structure.is(o.obj) || lastLoci.loci.kind !== 'element-loci') return;
if (lastLoci.loci.structure === o.obj.data) {
lastLoci = Representation.Loci.Empty;
}
});
this.subscribeObservable(this.plugin.events.state.object.updated, o => {
if (!PluginStateObject.Molecule.Structure.is(o.oldObj) || lastLoci.loci.kind !== 'element-loci') return;
if (lastLoci.loci.structure === o.oldObj.data) {
lastLoci = Representation.Loci.Empty;
}
});
this.subscribeObservable(this.plugin.behaviors.canvas3d.click, ({ current, buttons, modifiers }) => { this.subscribeObservable(this.plugin.behaviors.canvas3d.click, ({ current, buttons, modifiers }) => {
if (buttons !== ButtonsType.Flag.Secondary || this.params.view.name !== 'selection-box') return; if (buttons !== ButtonsType.Flag.Secondary || this.params.view.name !== 'selection-box') return;
...@@ -193,6 +208,13 @@ export namespace VolumeStreaming { ...@@ -193,6 +208,13 @@ export namespace VolumeStreaming {
const root = this.getStructureRoot(ref); const root = this.getStructureRoot(ref);
if (!root || !root.obj || root.obj !== parent.obj) return; if (!root || !root.obj || root.obj !== parent.obj) return;
if (Representation.Loci.areEqual(lastLoci, current)) {
lastLoci = Representation.Loci.Empty;
this.updateDynamicBox(ref, Box3D.empty());
return;
}
lastLoci = current;
const loci = StructureElement.Loci.extendToWholeResidues(current.loci); const loci = StructureElement.Loci.extendToWholeResidues(current.loci);
const box = StructureElement.Loci.getBoundary(loci).box; const box = StructureElement.Loci.getBoundary(loci).box;
this.updateDynamicBox(ref, box); this.updateDynamicBox(ref, box);
......
...@@ -180,11 +180,15 @@ ...@@ -180,11 +180,15 @@
line-height: $row-height; line-height: $row-height;
float: left; float: left;
margin-right: $control-spacing; margin-right: $control-spacing;
background-color: $msp-form-control-background;
> button {
background-color: $msp-form-control-background;
}
> select { > select {
display: inline-block; display: inline-block;
width: 200px; width: 200px;
margin-right: $control-spacing;
} }
} }
......
...@@ -9,7 +9,7 @@ import { createRenderObject, GraphicsRenderObject } from 'mol-gl/render-object'; ...@@ -9,7 +9,7 @@ import { createRenderObject, GraphicsRenderObject } from 'mol-gl/render-object';
import { Representation } from '../representation'; import { Representation } from '../representation';
import { Loci, EmptyLoci, isEveryLoci } from 'mol-model/loci'; import { Loci, EmptyLoci, isEveryLoci } from 'mol-model/loci';
import { ValueCell } from 'mol-util'; import { ValueCell } from 'mol-util';
import { Shape } from 'mol-model/shape'; import { Shape, ShapeGroup } from 'mol-model/shape';
import { OrderedSet, Interval } from 'mol-data/int'; import { OrderedSet, Interval } from 'mol-data/int';
import { ParamDefinition as PD } from 'mol-util/param-definition'; import { ParamDefinition as PD } from 'mol-util/param-definition';
import { createTransform, TransformData } from 'mol-geo/geometry/transform-data'; import { createTransform, TransformData } from 'mol-geo/geometry/transform-data';
...@@ -170,7 +170,7 @@ export function ShapeRepresentation<D, G extends Geometry, P extends Geometry.Pa ...@@ -170,7 +170,7 @@ export function ShapeRepresentation<D, G extends Geometry, P extends Geometry.Pa
getLoci(pickingId: PickingId) { getLoci(pickingId: PickingId) {
const { objectId, groupId, instanceId } = pickingId const { objectId, groupId, instanceId } = pickingId
if (_renderObject && _renderObject.id === objectId) { if (_renderObject && _renderObject.id === objectId) {
return Shape.Loci(_shape, [{ ids: OrderedSet.ofSingleton(groupId) }], instanceId) return ShapeGroup.Loci(_shape, [{ ids: OrderedSet.ofSingleton(groupId) }], instanceId)
} }
return EmptyLoci return EmptyLoci
}, },
...@@ -210,7 +210,7 @@ function createShapeTransform(transforms: Mat4[], transformData?: TransformData) ...@@ -210,7 +210,7 @@ function createShapeTransform(transforms: Mat4[], transformData?: TransformData)
} }
function eachShapeGroup(loci: Loci, shape: Shape, apply: (interval: Interval) => boolean) { function eachShapeGroup(loci: Loci, shape: Shape, apply: (interval: Interval) => boolean) {
if (!Shape.isLoci(loci)) return false if (!ShapeGroup.isLoci(loci)) return false
if (loci.shape !== shape) return false if (loci.shape !== shape) return false
let changed = false let changed = false
const { groupCount } = shape const { groupCount } = shape
...@@ -233,7 +233,7 @@ function eachShapeGroup(loci: Loci, shape: Shape, apply: (interval: Interval) => ...@@ -233,7 +233,7 @@ function eachShapeGroup(loci: Loci, shape: Shape, apply: (interval: Interval) =>
export namespace ShapeGroupIterator { export namespace ShapeGroupIterator {
export function fromShape(shape: Shape): LocationIterator { export function fromShape(shape: Shape): LocationIterator {
const instanceCount = shape.transforms.length const instanceCount = shape.transforms.length
const location = Shape.Location(shape) const location = ShapeGroup.Location(shape)
const getLocation = (groupIndex: number, instanceIndex: number) => { const getLocation = (groupIndex: number, instanceIndex: number) => {
location.group = groupIndex location.group = groupIndex
location.instance = instanceIndex location.instance = instanceIndex
......
...@@ -35,7 +35,9 @@ export function getNucleotideElementLoci(pickingId: PickingId, structureGroup: S ...@@ -35,7 +35,9 @@ export function getNucleotideElementLoci(pickingId: PickingId, structureGroup: S
if (id === objectId) { if (id === objectId) {
const { structure, group } = structureGroup const { structure, group } = structureGroup
const unit = group.units[instanceId] const unit = group.units[instanceId]
return getResidueLoci(structure, unit, unit.polymerElements[groupId]) if (Unit.isAtomic(unit)) {
return getResidueLoci(structure, unit, unit.polymerElements[groupId])
}
} }
return EmptyLoci return EmptyLoci
} }
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
import { ColorTheme } from '../color'; import { ColorTheme } from '../color';
import { Color } from 'mol-util/color'; import { Color } from 'mol-util/color';
import { Location } from 'mol-model/location'; import { Location } from 'mol-model/location';
import { Shape } from 'mol-model/shape'; import { ShapeGroup } from 'mol-model/shape';
import { ParamDefinition as PD } from 'mol-util/param-definition' import { ParamDefinition as PD } from 'mol-util/param-definition'
import { ThemeDataContext } from 'mol-theme/theme'; import { ThemeDataContext } from 'mol-theme/theme';
...@@ -25,7 +25,7 @@ export function ShapeGroupColorTheme(ctx: ThemeDataContext, props: PD.Values<Sha ...@@ -25,7 +25,7 @@ export function ShapeGroupColorTheme(ctx: ThemeDataContext, props: PD.Values<Sha
factory: ShapeGroupColorTheme, factory: ShapeGroupColorTheme,
granularity: 'groupInstance', granularity: 'groupInstance',
color: (location: Location): Color => { color: (location: Location): Color => {
if (Shape.isLocation(location)) { if (ShapeGroup.isLocation(location)) {
return location.shape.getColor(location.group, location.instance) return location.shape.getColor(location.group, location.instance)
} }
return DefaultColor return DefaultColor
......
...@@ -33,6 +33,8 @@ export function labelFirst(loci: Loci): string { ...@@ -33,6 +33,8 @@ export function labelFirst(loci: Loci): string {
case 'link-loci': case 'link-loci':
const link = loci.links[0] const link = loci.links[0]
return link ? linkLabel(link) : 'Unknown' return link ? linkLabel(link) : 'Unknown'
case 'shape-loci':
return loci.shape.name
case 'group-loci': case 'group-loci':
const g = loci.groups[0] const g = loci.groups[0]
if (g) { if (g) {
......
...@@ -5,7 +5,7 @@ ...@@ -5,7 +5,7 @@
*/ */
import { Location } from 'mol-model/location'; import { Location } from 'mol-model/location';
import { Shape } from 'mol-model/shape'; import { ShapeGroup } from 'mol-model/shape';
import { ParamDefinition as PD } from 'mol-util/param-definition' import { ParamDefinition as PD } from 'mol-util/param-definition'
import { ThemeDataContext } from 'mol-theme/theme'; import { ThemeDataContext } from 'mol-theme/theme';
import { SizeTheme } from 'mol-theme/size'; import { SizeTheme } from 'mol-theme/size';
...@@ -24,7 +24,7 @@ export function ShapeGroupSizeTheme(ctx: ThemeDataContext, props: PD.Values<Shap ...@@ -24,7 +24,7 @@ export function ShapeGroupSizeTheme(ctx: ThemeDataContext, props: PD.Values<Shap
factory: ShapeGroupSizeTheme, factory: ShapeGroupSizeTheme,
granularity: 'groupInstance', granularity: 'groupInstance',
size: (location: Location): number => { size: (location: Location): number => {
if (Shape.isLocation(location)) { if (ShapeGroup.isLocation(location)) {
return location.shape.getSize(location.group, location.instance) return location.shape.getSize(location.group, location.instance)
} }
return DefaultSize return DefaultSize
......
...@@ -15,6 +15,9 @@ import { ColorNames } from 'mol-util/color/tables'; ...@@ -15,6 +15,9 @@ import { ColorNames } from 'mol-util/color/tables';
import { Mesh } from 'mol-geo/geometry/mesh/mesh'; import { Mesh } from 'mol-geo/geometry/mesh/mesh';
import { labelFirst } from 'mol-theme/label'; import { labelFirst } from 'mol-theme/label';
import { RuntimeContext, Progress } from 'mol-task'; import { RuntimeContext, Progress } from 'mol-task';
import { Representation } from 'mol-repr/representation';
import { MarkerAction } from 'mol-geo/geometry/marker-data';
import { EveryLoci } from 'mol-model/loci';
const parent = document.getElementById('app')! const parent = document.getElementById('app')!
parent.style.width = '100%' parent.style.width = '100%'
...@@ -34,14 +37,23 @@ info.style.right = '20px' ...@@ -34,14 +37,23 @@ info.style.right = '20px'
info.style.color = 'white' info.style.color = 'white'
parent.appendChild(info) parent.appendChild(info)
let prevReprLoci = Representation.Loci.Empty
const canvas3d = Canvas3D.create(canvas, parent) const canvas3d = Canvas3D.create(canvas, parent)
canvas3d.animate() canvas3d.animate()
canvas3d.input.move.subscribe(async ({x, y}) => { canvas3d.input.move.subscribe(async ({x, y}) => {
const pickingId = await canvas3d.identify(x, y) const pickingId = await canvas3d.identify(x, y)
let label = '' let label = ''
if (pickingId) { if (pickingId) {
const { loci } = canvas3d.getLoci(pickingId) const reprLoci = canvas3d.getLoci(pickingId)
label = labelFirst(loci) label = labelFirst(reprLoci.loci)
if (!Representation.Loci.areEqual(prevReprLoci, reprLoci)) {
canvas3d.mark(prevReprLoci, MarkerAction.RemoveHighlight)
canvas3d.mark(reprLoci, MarkerAction.Highlight)
prevReprLoci = reprLoci
}
} else {
canvas3d.mark({ loci: EveryLoci }, MarkerAction.RemoveHighlight)
prevReprLoci = Representation.Loci.Empty
} }
info.innerText = label info.innerText = label
}) })
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment