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

mol-model Structure distance checking

parent 51ef3f36
No related branches found
No related tags found
No related merge requests found
...@@ -4,8 +4,9 @@ ...@@ -4,8 +4,9 @@
* @author David Sehnal <david.sehnal@gmail.com> * @author David Sehnal <david.sehnal@gmail.com>
*/ */
import { Structure, StructureElement } from '../structure'; import { Structure, StructureElement, Unit } from '../structure';
import { now } from 'mol-task'; import { now } from 'mol-task';
import { ElementIndex } from '../model';
export interface QueryContextView { export interface QueryContextView {
readonly element: StructureElement; readonly element: StructureElement;
...@@ -26,6 +27,11 @@ export class QueryContext implements QueryContextView { ...@@ -26,6 +27,11 @@ export class QueryContext implements QueryContextView {
readonly element: StructureElement = StructureElement.create(); readonly element: StructureElement = StructureElement.create();
currentStructure: Structure = void 0 as any; currentStructure: Structure = void 0 as any;
setElement(unit: Unit, e: ElementIndex) {
this.element.unit = unit;
this.element.element = e;
}
pushCurrentElement(): StructureElement { pushCurrentElement(): StructureElement {
this.currentElementStack[this.currentElementStack.length] = this.element; this.currentElementStack[this.currentElementStack.length] = this.element;
(this.element as StructureElement) = StructureElement.create(); (this.element as StructureElement) = StructureElement.create();
......
...@@ -107,7 +107,7 @@ export interface WithinParams { ...@@ -107,7 +107,7 @@ export interface WithinParams {
target: StructureQuery, target: StructureQuery,
minRadius?: number, minRadius?: number,
maxRadius: number, maxRadius: number,
atomRadius?: QueryFn<number>, elementRadius?: QueryFn<number>,
invert?: boolean invert?: boolean
} }
...@@ -120,12 +120,12 @@ export function within(params: WithinParams): StructureQuery { ...@@ -120,12 +120,12 @@ export function within(params: WithinParams): StructureQuery {
selection: params.query(queryCtx), selection: params.query(queryCtx),
target: params.target(queryCtx), target: params.target(queryCtx),
maxRadius: params.maxRadius, maxRadius: params.maxRadius,
minRadius: params.minRadius ? params.minRadius : 0, minRadius: params.minRadius ? Math.max(0, params.minRadius) : 0,
atomRadius: params.atomRadius || _zeroRadius, elementRadius: params.elementRadius!,
invert: !!params.invert, invert: !!params.invert,
} }
if (ctx.minRadius === 0 && ctx.atomRadius === _zeroRadius) { if (ctx.minRadius === 0 && typeof params.minRadius === 'undefined') {
return withinMaxRadius(ctx); return withinMaxRadius(ctx);
} else { } else {
// TODO // TODO
...@@ -142,7 +142,7 @@ interface WithinContext { ...@@ -142,7 +142,7 @@ interface WithinContext {
minRadius: number, minRadius: number,
maxRadius: number, maxRadius: number,
invert: boolean, invert: boolean,
atomRadius: QueryFn<number> elementRadius: QueryFn<number>
} }
function withinMaxRadius({ queryCtx, selection, target, maxRadius, invert }: WithinContext) { function withinMaxRadius({ queryCtx, selection, target, maxRadius, invert }: WithinContext) {
const targetLookup = StructureSelection.unionStructure(target).lookup3d; const targetLookup = StructureSelection.unionStructure(target).lookup3d;
...@@ -151,35 +151,19 @@ function withinMaxRadius({ queryCtx, selection, target, maxRadius, invert }: Wit ...@@ -151,35 +151,19 @@ function withinMaxRadius({ queryCtx, selection, target, maxRadius, invert }: Wit
const pos = Vec3.zero(); const pos = Vec3.zero();
StructureSelection.forEach(selection, (s, sI) => { StructureSelection.forEach(selection, (s, sI) => {
const { units } = s; const { units } = s;
let withinRadius = false; let withinRadius = false;
for (let i = 0, _i = units.length; i < _i; i++) { for (let i = 0, _i = units.length; i < _i; i++) {
const unit = units[i]; const unit = units[i];
const { elements, conformation } = unit; const { elements, conformation: { position, r } } = unit;
switch (unit.kind) {
case Unit.Kind.Atomic:
// TODO: assign radius to gaussian elements?
case Unit.Kind.Gaussians:
for (let i = 0, _i = elements.length; i < _i; i++) { for (let i = 0, _i = elements.length; i < _i; i++) {
conformation.position(elements[i], pos); const e = elements[i];
if (targetLookup.check(pos[0], pos[1], pos[2], maxRadius)) { position(e, pos);
if (targetLookup.check(pos[0], pos[1], pos[2], maxRadius + r(e))) {
withinRadius = true; withinRadius = true;
break; break;
} }
} }
break;
case Unit.Kind.Spheres:
const radius = unit.coarseConformation.radius;
for (let i = 0, _i = elements.length; i < _i; i++) {
conformation.position(elements[i], pos);
if (targetLookup.check(pos[0], pos[1], pos[2], maxRadius + radius[elements[i]])) {
withinRadius = true;
break;
}
}
break;
}
if (withinRadius) break; if (withinRadius) break;
} }
if (invert) withinRadius = !withinRadius; if (invert) withinRadius = !withinRadius;
......
/**
* Copyright (c) 2017 mol* contributors, licensed under MIT, See LICENSE file for more info.
*
* @author David Sehnal <david.sehnal@gmail.com>
*/
import { Structure, Unit } from '../../structure'
import { Vec3 } from 'mol-math/linear-algebra';
import { QueryFn, QueryContext } from '../context';
export function checkStructureMinMaxDistance(ctx: QueryContext, a: Structure, b: Structure, minDist: number, maxDist: number, elementRadius: QueryFn<number>) {
if (a.elementCount === 0 || b.elementCount === 0) return true;
if (a.elementCount <= b.elementCount) return MinMaxDist.check(ctx, a, b, minDist, maxDist, elementRadius);
return MinMaxDist.check(ctx, b, a, minDist, maxDist, elementRadius);
}
export function checkStructureMaxRadiusDistance(ctx: QueryContext, a: Structure, b: Structure, maxDist: number, elementRadius: QueryFn<number>) {
if (a.elementCount === 0 || b.elementCount === 0) return true;
if (a.elementCount <= b.elementCount) return MaxRadiusDist.check(ctx, a, b, maxDist, elementRadius);
return MaxRadiusDist.check(ctx, b, a, maxDist, elementRadius);
}
namespace MinMaxDist {
const enum Result {
BelowMin,
WithinMax,
Miss
}
const distVec = Vec3.zero();
function inUnit(ctx: QueryContext, unit: Unit, p: Vec3, eRadius: number, minDist: number, maxDist: number, elementRadius: QueryFn<number>) {
const { elements, conformation: { position } } = unit, dV = distVec;
ctx.element.unit = unit;
let withinRange = false;
for (let i = 0, _i = elements.length; i < _i; i++) {
const e = elements[i];
ctx.element.element = e;
const d = Math.max(0, Vec3.distance(p, position(e, dV)) - eRadius - elementRadius(ctx));
if (d < minDist) return Result.BelowMin;
if (d < maxDist) withinRange = true;
}
return withinRange ? Result.WithinMax : Result.Miss;
}
export function toPoint(ctx: QueryContext, s: Structure, point: Vec3, radius: number, minDist: number, maxDist: number, elementRadius: QueryFn<number>) {
const { units } = s;
let withinRange = false;
for (let i = 0, _i = units.length; i < _i; i++) {
const iu = inUnit(ctx, units[i], point, radius, minDist, maxDist, elementRadius);
if (iu === Result.BelowMin) return Result.BelowMin;
if (iu === Result.WithinMax) withinRange = true;
}
return withinRange ? Result.WithinMax : Result.Miss;
}
const distPivot = Vec3.zero();
export function check(ctx: QueryContext, a: Structure, b: Structure, minDist: number, maxDist: number, elementRadius: QueryFn<number>) {
if (a.elementCount === 0 || b.elementCount === 0) return 0;
const { units } = a;
let withinRange = false;
for (let i = 0, _i = units.length; i < _i; i++) {
const unit = units[i];
const { elements, conformation: { position } } = unit;
for (let i = 0, _i = elements.length; i < _i; i++) {
const e = elements[i];
ctx.setElement(unit, e);
const tp = toPoint(ctx, b, position(e, distPivot), elementRadius(ctx), minDist, maxDist, elementRadius);
if (tp === Result.BelowMin) return Result.BelowMin;
if (tp === Result.WithinMax) withinRange = true;
}
}
return withinRange;
}
}
namespace MaxRadiusDist {
const distVec = Vec3.zero();
function inUnit(ctx: QueryContext, unit: Unit, p: Vec3, eRadius: number, maxDist: number, elementRadius: QueryFn<number>) {
const { elements, conformation: { position } } = unit, dV = distVec;
ctx.element.unit = unit;
for (let i = 0, _i = elements.length; i < _i; i++) {
const e = elements[i];
ctx.element.element = e;
if (Math.max(0, Vec3.distance(p, position(e, dV)) - eRadius - elementRadius(ctx)) <= maxDist) return true;
}
return false;
}
export function toPoint(ctx: QueryContext, s: Structure, point: Vec3, radius: number, maxDist: number, elementRadius: QueryFn<number>) {
const { units } = s;
for (let i = 0, _i = units.length; i < _i; i++) {
if (inUnit(ctx, units[i], point, radius, maxDist, elementRadius)) return true;
}
return false;
}
const distPivot = Vec3.zero();
export function check(ctx: QueryContext, a: Structure, b: Structure, maxDist: number, elementRadius: QueryFn<number>) {
if (a.elementCount === 0 || b.elementCount === 0) return 0;
const { units } = a;
for (let i = 0, _i = units.length; i < _i; i++) {
const unit = units[i];
const { elements, conformation: { position } } = unit;
for (let i = 0, _i = elements.length; i < _i; i++) {
const e = elements[i];
ctx.setElement(unit, e);
if (toPoint(ctx, b, position(e, distPivot), elementRadius(ctx), maxDist, elementRadius)) return true;
}
}
return false;
}
}
\ No newline at end of file
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment