From 27f10d52d05fa8b2e350a1e31f7db346e8fb67a8 Mon Sep 17 00:00:00 2001
From: David Sehnal <david.sehnal@gmail.com>
Date: Fri, 1 Mar 2019 22:42:37 +0100
Subject: [PATCH] mol-plugin: StructureElement.Loci.getBoundary

---
 src/mol-model/loci.ts                         | 20 +-----------
 src/mol-model/structure/structure/element.ts  | 32 +++++++++++++++++++
 .../dynamic/volume-streaming/behavior.ts      | 17 +++++-----
 3 files changed, 41 insertions(+), 28 deletions(-)

diff --git a/src/mol-model/loci.ts b/src/mol-model/loci.ts
index 34bb4d4e6..35cad50ed 100644
--- a/src/mol-model/loci.ts
+++ b/src/mol-model/loci.ts
@@ -81,25 +81,7 @@ namespace Loci {
         if (loci.kind === 'structure-loci') {
             return Sphere3D.copy(boundingSphere, loci.structure.boundary.sphere)
         } else if (loci.kind === 'element-loci') {
-            for (const e of loci.elements) {
-                const { indices } = e;
-                const pos = e.unit.conformation.position;
-                const { elements } = e.unit;
-                for (let i = 0, _i = OrderedSet.size(indices); i < _i; i++) {
-                    pos(elements[OrderedSet.getAt(indices, i)], tempPos);
-                    sphereHelper.includeStep(tempPos);
-                }
-            }
-            sphereHelper.finishedIncludeStep();
-            for (const e of loci.elements) {
-                const { indices } = e;
-                const pos = e.unit.conformation.position;
-                const { elements } = e.unit;
-                for (let i = 0, _i = OrderedSet.size(indices); i < _i; i++) {
-                    pos(elements[OrderedSet.getAt(indices, i)], tempPos);
-                    sphereHelper.radiusStep(tempPos);
-                }
-            }
+            return StructureElement.Loci.getBoundary(loci).sphere;
         } else if (loci.kind === 'link-loci') {
             for (const e of loci.links) {
                 e.aUnit.conformation.position(e.aUnit.elements[e.aIndex], tempPos);
diff --git a/src/mol-model/structure/structure/element.ts b/src/mol-model/structure/structure/element.ts
index 4e5148225..1bd19cde9 100644
--- a/src/mol-model/structure/structure/element.ts
+++ b/src/mol-model/structure/structure/element.ts
@@ -9,6 +9,9 @@ import Unit from './unit'
 import { ElementIndex } from '../model';
 import { ResidueIndex, ChainIndex } from '../model/indexing';
 import Structure from './structure';
+import { Boundary } from './util/boundary';
+import { BoundaryHelper } from 'mol-math/geometry/boundary-helper';
+import { Vec3 } from 'mol-math/linear-algebra';
 
 interface StructureElement<U = Unit> {
     readonly kind: 'element-location',
@@ -208,6 +211,35 @@ namespace StructureElement {
 
             return Loci(loci.structure, elements);
         }
+
+        const boundaryHelper = new BoundaryHelper(), tempPos = Vec3.zero();
+        export function getBoundary(loci: Loci): Boundary {
+            boundaryHelper.reset(0);
+
+            for (const e of loci.elements) {
+                const { indices } = e;
+                const pos = e.unit.conformation.position, r = e.unit.conformation.r;
+                const { elements } = e.unit;
+                for (let i = 0, _i = OrderedSet.size(indices); i < _i; i++) {
+                    const eI = elements[OrderedSet.getAt(indices, i)];
+                    pos(eI, tempPos);
+                    boundaryHelper.boundaryStep(tempPos, r(eI));
+                }
+            }
+            boundaryHelper.finishBoundaryStep();
+            for (const e of loci.elements) {
+                const { indices } = e;
+                const pos = e.unit.conformation.position, r = e.unit.conformation.r;
+                const { elements } = e.unit;
+                for (let i = 0, _i = OrderedSet.size(indices); i < _i; i++) {
+                    const eI = elements[OrderedSet.getAt(indices, i)];
+                    pos(eI, tempPos);
+                    boundaryHelper.extendStep(tempPos, r(eI));
+                }
+            }
+
+            return { box: boundaryHelper.getBox(), sphere: boundaryHelper.getSphere() };
+        }
     }
 }
 
diff --git a/src/mol-plugin/behavior/dynamic/volume-streaming/behavior.ts b/src/mol-plugin/behavior/dynamic/volume-streaming/behavior.ts
index d2ce4aa51..846b9d299 100644
--- a/src/mol-plugin/behavior/dynamic/volume-streaming/behavior.ts
+++ b/src/mol-plugin/behavior/dynamic/volume-streaming/behavior.ts
@@ -19,7 +19,6 @@ import { Box3D } from 'mol-math/geometry';
 import { urlCombine } from 'mol-util/url';
 import { volumeFromDensityServerData } from 'mol-model-formats/volume/density-server';
 import { StructureElement } from 'mol-model/structure';
-import { Loci } from 'mol-model/loci';
 import { CreateVolumeStreamingBehavior } from './transformers';
 
 export class VolumeStreaming extends PluginStateObject.CreateBehavior<VolumeStreaming.Behavior>({ name: 'Volume Streaming' }) { }
@@ -150,18 +149,15 @@ export namespace VolumeStreaming {
 
             this.subscribeObservable(this.plugin.events.canvas3d.click, ({ current }) => {
                 if (this.params.view.name !== 'selection-box') return;
+                // TODO: support link loci as well?
+                // Perhaps structure loci too?
                 if (!StructureElement.isLoci(current.loci)) return;
 
                 // TODO: check if it's the related structure
-
                 const loci = StructureElement.Loci.extendToWholeResidues(current.loci);
 
                 const eR = this.params.view.params.radius;
-
-                const sphere = Loci.getBoundingSphere(loci)!;
-                const r = Vec3.create(sphere.radius + eR, sphere.radius + eR, sphere.radius + eR);
-                const box = Box3D.create(Vec3.sub(Vec3.zero(), sphere.center, r), Vec3.add(Vec3.zero(), sphere.center, r));
-
+                const box = StructureElement.Loci.getBoundary(loci).box;
                 const update = this.plugin.state.dataState.build().to(ref)
                     .update(CreateVolumeStreamingBehavior, old => ({
                         ...old,
@@ -188,10 +184,13 @@ export namespace VolumeStreaming {
                 case 'box':
                     box = Box3D.create(params.view.params.bottomLeft, params.view.params.topRight);
                     break;
-                case 'selection-box':
-                    box = Box3D.create(params.view.params.bottomLeft, params.view.params.topRight);
+                case 'selection-box': {
+                    box = Box3D.create(Vec3.clone(params.view.params.bottomLeft), Vec3.clone(params.view.params.topRight));
+                    const r = params.view.params.radius;
                     emptyData = Box3D.volume(box) < 0.0001;
+                    Box3D.expand(box, box, Vec3.create(r, r, r));
                     break;
+                }
                 case 'cell':
                     box = this.info.kind === 'x-ray'
                         ? this.info.structure.boundary.box
-- 
GitLab