Переглянути джерело

added structure OrientationRepresentation

Alexander Rose 5 роки тому
батько
коміт
784b29805a

+ 2 - 0
src/mol-repr/structure/registry.ts

@@ -17,6 +17,7 @@ import { StructureRepresentationState } from './representation';
 import { PuttyRepresentationProvider } from './representation/putty';
 import { MolecularSurfaceRepresentationProvider } from './representation/molecular-surface';
 import { EllipsoidRepresentationProvider } from './representation/ellipsoid';
+import { OrientationRepresentationProvider } from './representation/orientation';
 
 export class StructureRepresentationRegistry extends RepresentationRegistry<Structure, StructureRepresentationState> {
     constructor() {
@@ -37,6 +38,7 @@ export const BuiltInStructureRepresentations = {
     'gaussian-surface': GaussianSurfaceRepresentationProvider,
     // 'gaussian-volume': GaussianVolumeRepresentationProvider, // TODO disabled for now, needs more work
     'molecular-surface': MolecularSurfaceRepresentationProvider,
+    'orientation': OrientationRepresentationProvider,
     'point': PointRepresentationProvider,
     'putty': PuttyRepresentationProvider,
     'spacefill': SpacefillRepresentationProvider,

+ 44 - 0
src/mol-repr/structure/representation/orientation.ts

@@ -0,0 +1,44 @@
+/**
+ * Copyright (c) 2019 mol* contributors, licensed under MIT, See LICENSE file for more info.
+ *
+ * @author Alexander Rose <alexander.rose@weirdbyte.de>
+ */
+
+import { UnitsRepresentation } from '../units-representation';
+import { ParamDefinition as PD } from '../../../mol-util/param-definition';
+import { StructureRepresentation, StructureRepresentationProvider, StructureRepresentationStateBuilder } from '../representation';
+import { Representation, RepresentationParamsGetter, RepresentationContext } from '../../../mol-repr/representation';
+import { ThemeRegistryContext } from '../../../mol-theme/theme';
+import { Structure } from '../../../mol-model/structure';
+import { OrientationEllipsoidMeshParams, OrientationEllipsoidMeshVisual } from '../visual/orientation-ellipsoid-mesh';
+
+const OrientationVisuals = {
+    'orientation-ellipsoid-mesh': (ctx: RepresentationContext, getParams: RepresentationParamsGetter<Structure, OrientationEllipsoidMeshParams>) => UnitsRepresentation('Orientation ellipsoid mesh', ctx, getParams, OrientationEllipsoidMeshVisual),
+}
+type OrientationVisualName = keyof typeof OrientationVisuals
+const OrientationVisualOptions = Object.keys(OrientationVisuals).map(name => [name, name] as [OrientationVisualName, string])
+
+export const OrientationParams = {
+    ...OrientationEllipsoidMeshParams,
+    visuals: PD.MultiSelect<OrientationVisualName>(['orientation-ellipsoid-mesh'], OrientationVisualOptions),
+}
+export type OrientationParams = typeof OrientationParams
+export function getOrientationParams(ctx: ThemeRegistryContext, structure: Structure) {
+    return PD.clone(OrientationParams)
+}
+
+export type OrientationRepresentation = StructureRepresentation<OrientationParams>
+export function OrientationRepresentation(ctx: RepresentationContext, getParams: RepresentationParamsGetter<Structure, OrientationParams>): OrientationRepresentation {
+    return Representation.createMulti('Orientation', ctx, getParams, StructureRepresentationStateBuilder, OrientationVisuals as unknown as Representation.Def<Structure, OrientationParams>)
+}
+
+export const OrientationRepresentationProvider: StructureRepresentationProvider<OrientationParams> = {
+    label: 'Orientation',
+    description: 'Displays orientation ellipsoids for polymer chains.',
+    factory: OrientationRepresentation,
+    getParams: getOrientationParams,
+    defaultValues: PD.getDefaultValues(OrientationParams),
+    defaultColorTheme: 'polymer-id',
+    defaultSizeTheme: 'uniform',
+    isApplicable: (structure: Structure) => structure.elementCount > 0
+}

+ 115 - 0
src/mol-repr/structure/visual/orientation-ellipsoid-mesh.ts

@@ -0,0 +1,115 @@
+/**
+ * Copyright (c) 2019 mol* contributors, licensed under MIT, See LICENSE file for more info.
+ *
+ * @author Alexander Rose <alexander.rose@weirdbyte.de>
+ */
+
+import { ParamDefinition as PD } from '../../../mol-util/param-definition';
+import { UnitsMeshParams, UnitsVisual, UnitsMeshVisual, StructureGroup } from '../../../mol-repr/structure/units-visual';
+import { VisualUpdateState } from '../../../mol-repr/util';
+import { VisualContext } from '../../../mol-repr/visual';
+import { Unit, Structure, StructureElement } from '../../../mol-model/structure';
+import { Theme } from '../../../mol-theme/theme';
+import { Mesh } from '../../../mol-geo/geometry/mesh/mesh';
+import { MeshBuilder } from '../../../mol-geo/geometry/mesh/mesh-builder';
+import { Vec3 } from '../../../mol-math/linear-algebra';
+import { addEllipsoid } from '../../../mol-geo/geometry/mesh/builder/ellipsoid';
+import { Axes3D } from '../../../mol-math/geometry';
+import { PickingId } from '../../../mol-geo/geometry/picking';
+import { OrderedSet, Interval } from '../../../mol-data/int';
+import { EmptyLoci, Loci } from '../../../mol-model/loci';
+import { UnitIndex } from '../../../mol-model/structure/structure/element/element';
+import { LocationIterator } from '../../../mol-geo/util/location-iterator';
+
+export const OrientationEllipsoidMeshParams = {
+    ...UnitsMeshParams,
+    sizeFactor: PD.Numeric(1, { min: 0, max: 2, step: 0.1 }),
+    detail: PD.Numeric(0, { min: 0, max: 3, step: 1 }),
+}
+export type OrientationEllipsoidMeshParams = typeof OrientationEllipsoidMeshParams
+
+export function OrientationEllipsoidMeshVisual(materialId: number): UnitsVisual<OrientationEllipsoidMeshParams> {
+    return UnitsMeshVisual<OrientationEllipsoidMeshParams>({
+        defaultProps: PD.getDefaultValues(OrientationEllipsoidMeshParams),
+        createGeometry: createOrientationEllipsoidMesh,
+        createLocationIterator: UnitIterator,
+        getLoci: getUnitLoci,
+        eachLocation: eachUnit,
+        setUpdateState: (state: VisualUpdateState, newProps: PD.Values<OrientationEllipsoidMeshParams>, currentProps: PD.Values<OrientationEllipsoidMeshParams>) => {
+            state.createGeometry = (
+                newProps.sizeFactor !== currentProps.sizeFactor ||
+                newProps.detail !== currentProps.detail
+            )
+        }
+    }, materialId)
+}
+
+//
+
+export interface OrientationEllipsoidMeshProps {
+    detail: number,
+    sizeFactor: number,
+}
+
+export function createOrientationEllipsoidMesh(ctx: VisualContext, unit: Unit, structure: Structure, theme: Theme, props: OrientationEllipsoidMeshProps, mesh?: Mesh): Mesh {
+    if (unit.polymerElements.length === 0) return Mesh.createEmpty(mesh)
+
+    const { detail, sizeFactor } = props
+
+    const vertexCount = 256
+    const builderState = MeshBuilder.createState(vertexCount, vertexCount / 2, mesh)
+    const axes = unit.principalAxes.boxAxes
+    const { origin, dirA, dirB } = axes
+
+    const size = Axes3D.size(Vec3(), axes)
+    Vec3.scale(size, size, sizeFactor / 2)
+    const radiusScale = Vec3.create(size[2], size[1], size[0])
+
+    builderState.currentGroup = 0
+    addEllipsoid(builderState, origin, dirA, dirB, radiusScale, detail)
+
+    return MeshBuilder.getMesh(builderState)
+}
+
+//
+
+function UnitIterator(group: Unit.SymmetryGroup): LocationIterator {
+    const groupCount = 1
+    const instanceCount = group.units.length
+    const location = StructureElement.Location.create()
+    const getLocation = (groupIndex: number, instanceIndex: number) => {
+        const unit = group.units[instanceIndex]
+        location.unit = unit
+        location.element = unit.elements[groupIndex]
+        return location
+    }
+    return LocationIterator(groupCount, instanceCount, getLocation)
+}
+
+function getUnitLoci(pickingId: PickingId, structureGroup: StructureGroup, id: number) {
+    const { objectId, instanceId } = pickingId
+    if (id === objectId) {
+        const { structure, group } = structureGroup
+        const unit = group.units[instanceId]
+        const indices = OrderedSet.ofBounds(0, unit.elements.length) as OrderedSet<UnitIndex>
+        return StructureElement.Loci(structure, [{ unit, indices }])
+    }
+    return EmptyLoci
+}
+
+function eachUnit(loci: Loci, structureGroup: StructureGroup, apply: (interval: Interval) => boolean) {
+    let changed = false
+    if (!StructureElement.Loci.is(loci)) return false
+    const { structure, group } = structureGroup
+    if (!Structure.areEquivalent(loci.structure, structure)) return false
+    const elementCount = group.elements.length
+    for (const e of loci.elements) {
+        const unitIdx = group.unitIndexMap.get(e.unit.id)
+        if (unitIdx !== undefined) {
+            if (OrderedSet.size(e.indices) === elementCount) {
+                if (apply(Interval.ofSingleton(0))) changed = true
+            }
+        }
+    }
+    return changed
+}