Browse Source

add focus button to StructureSelectionControls

Alexander Rose 5 years ago
parent
commit
5f880e920b

+ 1 - 1
src/mol-model/loci.ts

@@ -104,7 +104,7 @@ namespace Loci {
     export function getBoundingSphere(loci: Loci, boundingSphere?: Sphere3D): Sphere3D | undefined {
         if (loci.kind === 'every-loci' || loci.kind === 'empty-loci') return void 0;
 
-        if (!boundingSphere) boundingSphere = Sphere3D.zero()
+        if (!boundingSphere) boundingSphere = Sphere3D()
         sphereHelper.reset();
 
         if (loci.kind === 'structure-loci') {

+ 1 - 2
src/mol-plugin/behavior/dynamic/camera.ts

@@ -36,12 +36,11 @@ export const FocusLoci = PluginBehavior.create<FocusLociProps>({
                 if (!this.ctx.canvas3d) return;
 
                 const p = this.params;
-                const durationMs = typeof p.durationMs === 'undefined' ? 250 : p.durationMs;
                 if (Binding.match(this.params.bindings.clickCenterFocus, buttons, modifiers)) {
                     const sphere = Loci.getBoundingSphere(current.loci);
                     if (sphere) {
                         const radius = Math.max(sphere.radius + p.extraRadius, p.minRadius);
-                        this.ctx.canvas3d.camera.focus(sphere.center, radius, durationMs);
+                        this.ctx.canvas3d.camera.focus(sphere.center, radius, p.durationMs);
                     }
                 }
             });

+ 27 - 6
src/mol-plugin/ui/structure/selection.tsx

@@ -5,7 +5,7 @@
  */
 
 import * as React from 'react';
-import { CollapsableControls } from '../base';
+import { CollapsableControls, CollapsableState } from '../base';
 import { StructureSelectionQueries, SelectionModifier } from '../../util/structure-selection-helper';
 import { ButtonSelect, Options } from '../controls/common';
 import { PluginCommands } from '../../command';
@@ -18,7 +18,13 @@ const StructureSelectionParams = {
     granularity: Interactivity.Params.granularity,
 }
 
-export class StructureSelectionControls extends CollapsableControls {
+interface StructureSelectionControlsState extends CollapsableState {
+    minRadius: number,
+    extraRadius: number,
+    durationMs: number
+}
+
+export class StructureSelectionControls<P, S extends StructureSelectionControlsState> extends CollapsableControls<P, S> {
     componentDidMount() {
         this.subscribe(this.plugin.events.interactivity.selectionUpdated, () => {
             this.forceUpdate()
@@ -38,6 +44,14 @@ export class StructureSelectionControls extends CollapsableControls {
         }
     }
 
+    focus = () => {
+        const { extraRadius, minRadius, durationMs } = this.state
+        const { sphere } = this.plugin.helpers.structureSelectionManager.getBoundary();
+        if (sphere.radius === 0) return
+        const radius = Math.max(sphere.radius + extraRadius, minRadius);
+        this.plugin.canvas3d.camera.focus(sphere.center, radius, durationMs);
+    }
+
     setProps = (p: { param: PD.Base<any>, name: string, value: any }) => {
         if (p.name === 'granularity') {
             PluginCommands.Interactivity.SetProps.dispatch(this.plugin, { props: { granularity: p.value } });
@@ -46,7 +60,7 @@ export class StructureSelectionControls extends CollapsableControls {
 
     get values () {
         return {
-            granularity: this.plugin.interactivity.props.granularity
+            granularity: this.plugin.interactivity.props.granularity,
         }
     }
 
@@ -62,8 +76,12 @@ export class StructureSelectionControls extends CollapsableControls {
     defaultState() {
         return {
             isCollapsed: false,
-            header: 'Selection'
-        }
+            header: 'Selection',
+
+            minRadius: 8,
+            extraRadius: 4,
+            durationMs: 250
+        } as S
     }
 
     renderControls() {
@@ -73,7 +91,10 @@ export class StructureSelectionControls extends CollapsableControls {
 
         return <div>
             <div className='msp-control-row msp-row-text'>
-                <div>{this.stats}</div>
+                <button className='msp-btn msp-btn-block' onClick={this.focus}>
+                    <span className={`msp-icon msp-icon-focus-on-visual`} style={{ position: 'absolute', left: '10px' }} />
+                    {this.stats}
+                </button>
             </div>
             <ParameterControls params={StructureSelectionParams} values={this.values} onChange={this.setProps} />
             <div className='msp-control-row'>

+ 36 - 0
src/mol-plugin/util/structure-element-selection.ts

@@ -12,6 +12,11 @@ import { StateObject } from '../../mol-state';
 import { PluginContext } from '../context';
 import { PluginStateObject } from '../state/objects';
 import { structureElementStatsLabel } from '../../mol-theme/label';
+import { Vec3 } from '../../mol-math/linear-algebra';
+import { BoundaryHelper } from '../../mol-math/geometry/boundary-helper';
+import { Boundary } from '../../mol-model/structure/structure/util/boundary';
+
+const boundaryHelper = new BoundaryHelper();
 
 export { StructureElementSelectionManager };
 class StructureElementSelectionManager {
@@ -30,6 +35,37 @@ class StructureElementSelectionManager {
         return this.entries.get(ref)!;
     }
 
+    getBoundary() {
+        const min = Vec3.create(Number.MAX_VALUE, Number.MAX_VALUE, Number.MAX_VALUE)
+        const max = Vec3.create(-Number.MAX_VALUE, -Number.MAX_VALUE, -Number.MAX_VALUE)
+
+        boundaryHelper.reset(0);
+
+        const boundaries: Boundary[] = []
+        this.entries.forEach(v => {
+            const loci = v.selection
+            if (!StructureElement.Loci.isEmpty(loci)) {
+                boundaries.push(StructureElement.Loci.getBoundary(loci))
+            }
+        })
+
+        for (let i = 0, il = boundaries.length; i < il; ++i) {
+            const { box, sphere } = boundaries[i];
+            Vec3.min(min, min, box.min);
+            Vec3.max(max, max, box.max);
+            boundaryHelper.boundaryStep(sphere.center, sphere.radius)
+        }
+
+        boundaryHelper.finishBoundaryStep();
+
+        for (let i = 0, il = boundaries.length; i < il; ++i) {
+            const { sphere } = boundaries[i];
+            boundaryHelper.extendStep(sphere.center, sphere.radius);
+        }
+
+        return { box: { min, max }, sphere: boundaryHelper.getSphere() };
+    }
+
     get stats() {
         let structureCount = 0
         let elementCount = 0