Skip to content
Snippets Groups Projects
Commit aff2cdc3 authored by David Sehnal's avatar David Sehnal
Browse files

mol-model/query include surroundings radius support

parent 20ee4149
No related branches found
No related tags found
No related merge requests found
...@@ -14,6 +14,7 @@ import { QueryContext, QueryFn } from '../context'; ...@@ -14,6 +14,7 @@ import { QueryContext, QueryFn } from '../context';
import { structureIntersect, structureSubtract } from '../utils/structure-set'; import { structureIntersect, structureSubtract } from '../utils/structure-set';
import { UniqueArray } from 'mol-data/generic'; import { UniqueArray } from 'mol-data/generic';
import { StructureSubsetBuilder } from '../../structure/util/subset-builder'; import { StructureSubsetBuilder } from '../../structure/util/subset-builder';
import StructureElement from '../../structure/element';
function getWholeResidues(ctx: QueryContext, source: Structure, structure: Structure) { function getWholeResidues(ctx: QueryContext, source: Structure, structure: Structure) {
const builder = source.subsetBuilder(true); const builder = source.subsetBuilder(true);
...@@ -59,8 +60,7 @@ export function wholeResidues(query: StructureQuery): StructureQuery { ...@@ -59,8 +60,7 @@ export function wholeResidues(query: StructureQuery): StructureQuery {
export interface IncludeSurroundingsParams { export interface IncludeSurroundingsParams {
radius: number, radius: number,
// TODO elementRadius?: QueryFn<number>,
// atomRadius?: Element.Property<number>,
wholeResidues?: boolean wholeResidues?: boolean
} }
...@@ -82,9 +82,88 @@ function getIncludeSurroundings(ctx: QueryContext, source: Structure, structure: ...@@ -82,9 +82,88 @@ function getIncludeSurroundings(ctx: QueryContext, source: Structure, structure:
return !!params.wholeResidues ? getWholeResidues(ctx, source, builder.getStructure()) : builder.getStructure(); return !!params.wholeResidues ? getWholeResidues(ctx, source, builder.getStructure()) : builder.getStructure();
} }
interface IncludeSurroundingsParamsWithRadius extends IncludeSurroundingsParams {
elementRadius: QueryFn<number>,
elementRadiusClosure: StructureElement.Property<number>,
sourceMaxRadius: number
}
function getIncludeSurroundingsWithRadius(ctx: QueryContext, source: Structure, structure: Structure, params: IncludeSurroundingsParamsWithRadius) {
const builder = new StructureUniqueSubsetBuilder(source);
const lookup = source.lookup3d;
const { elementRadius, elementRadiusClosure, sourceMaxRadius, radius } = params;
ctx.pushCurrentElement();
for (const unit of structure.units) {
ctx.element.unit = unit;
const { x, y, z } = unit.conformation;
const elements = unit.elements;
for (let i = 0, _i = elements.length; i < _i; i++) {
const e = elements[i];
ctx.element.element = e;
const eRadius = elementRadius(ctx);
lookup.findIntoBuilderWithRadius(x(e), y(e), z(e), eRadius, sourceMaxRadius, radius, elementRadiusClosure, builder);
}
ctx.throwIfTimedOut();
}
ctx.popCurrentElement();
return !!params.wholeResidues ? getWholeResidues(ctx, source, builder.getStructure()) : builder.getStructure();
}
function createElementRadiusFn(ctx: QueryContext, eRadius: QueryFn<number>): StructureElement.Property<number> {
return e => {
ctx.element.unit = e.unit;
ctx.element.element = e.element;
return eRadius(ctx);
}
}
function findStructureRadius(ctx: QueryContext, eRadius: QueryFn<number>) {
let r = 0;
for (const unit of ctx.inputStructure.units) {
ctx.element.unit = unit;
const elements = unit.elements;
for (let i = 0, _i = elements.length; i < _i; i++) {
const e = elements[i];
ctx.element.element = e;
const eR = eRadius(ctx);
if (eR > r) r = eR;
}
}
ctx.throwIfTimedOut();
return r;
}
export function includeSurroundings(query: StructureQuery, params: IncludeSurroundingsParams): StructureQuery { export function includeSurroundings(query: StructureQuery, params: IncludeSurroundingsParams): StructureQuery {
return ctx => { return ctx => {
const inner = query(ctx); const inner = query(ctx);
if (params.elementRadius) {
const prms: IncludeSurroundingsParamsWithRadius = {
...params,
elementRadius: params.elementRadius,
elementRadiusClosure: createElementRadiusFn(ctx, params.elementRadius),
sourceMaxRadius: findStructureRadius(ctx, params.elementRadius)
};
if (StructureSelection.isSingleton(inner)) {
const surr = getIncludeSurroundingsWithRadius(ctx, ctx.inputStructure, inner.structure, prms);
const ret = StructureSelection.Singletons(ctx.inputStructure, surr);
return ret;
} else {
const builder = new UniqueStructuresBuilder(ctx.inputStructure);
for (const s of inner.structures) {
builder.add(getIncludeSurroundingsWithRadius(ctx, ctx.inputStructure, s, prms));
}
return builder.getSelection();
}
}
if (StructureSelection.isSingleton(inner)) { if (StructureSelection.isSingleton(inner)) {
const surr = getIncludeSurroundings(ctx, ctx.inputStructure, inner.structure, params); const surr = getIncludeSurroundings(ctx, ctx.inputStructure, inner.structure, params);
const ret = StructureSelection.Singletons(ctx.inputStructure, surr); const ret = StructureSelection.Singletons(ctx.inputStructure, surr);
...@@ -218,4 +297,4 @@ export function expandProperty(query: StructureQuery, property: QueryFn): Struct ...@@ -218,4 +297,4 @@ export function expandProperty(query: StructureQuery, property: QueryFn): Struct
}; };
} }
// TODO: unionBy (skip this one?), cluster, includeConnected, includeSurroundings with "radii" // TODO: unionBy (skip this one?), cluster, includeConnected
\ No newline at end of file \ No newline at end of file
...@@ -10,6 +10,7 @@ import { Vec3 } from 'mol-math/linear-algebra'; ...@@ -10,6 +10,7 @@ import { Vec3 } from 'mol-math/linear-algebra';
import { computeStructureBoundary } from './boundary'; import { computeStructureBoundary } from './boundary';
import { OrderedSet } from 'mol-data/int'; import { OrderedSet } from 'mol-data/int';
import { StructureUniqueSubsetBuilder } from './unique-subset-builder'; import { StructureUniqueSubsetBuilder } from './unique-subset-builder';
import StructureElement from '../element';
export class StructureLookup3D { export class StructureLookup3D {
private unitLookup: Lookup3D; private unitLookup: Lookup3D;
...@@ -66,6 +67,39 @@ export class StructureLookup3D { ...@@ -66,6 +67,39 @@ export class StructureLookup3D {
} }
} }
findIntoBuilderWithRadius(x: number, y: number, z: number, pivotR: number, maxRadius: number, radius: number, eRadius: StructureElement.Property<number>, builder: StructureUniqueSubsetBuilder) {
const { units } = this.structure;
const closeUnits = this.unitLookup.find(x, y, z, radius);
if (closeUnits.count === 0) return;
const se = StructureElement.create();
const queryRadius = pivotR + maxRadius + radius;
for (let t = 0, _t = closeUnits.count; t < _t; t++) {
const unit = units[closeUnits.indices[t]];
Vec3.set(this.pivot, x, y, z);
if (!unit.conformation.operator.isIdentity) {
Vec3.transformMat4(this.pivot, this.pivot, unit.conformation.operator.inverse);
}
const unitLookup = unit.lookup3d;
const groupResult = unitLookup.find(this.pivot[0], this.pivot[1], this.pivot[2], queryRadius);
if (groupResult.count === 0) continue;
const elements = unit.elements;
se.unit = unit;
builder.beginUnit(unit.id);
for (let j = 0, _j = groupResult.count; j < _j; j++) {
se.element = elements[groupResult.indices[j]];
const rr = eRadius(se);
if (Math.sqrt(groupResult.squaredDistances[j]) - pivotR - rr > radius) continue;
builder.addElement(elements[groupResult.indices[j]]);
}
builder.commitUnit();
}
}
check(x: number, y: number, z: number, radius: number): boolean { check(x: number, y: number, z: number, radius: number): boolean {
const { units } = this.structure; const { units } = this.structure;
const closeUnits = this.unitLookup.find(x, y, z, radius); const closeUnits = this.unitLookup.find(x, y, z, radius);
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment