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

wip, mol-model/queries

parent 599ab540
No related branches found
No related tags found
No related merge requests found
...@@ -12,34 +12,32 @@ export interface QueryContextView { ...@@ -12,34 +12,32 @@ export interface QueryContextView {
} }
export class QueryContext implements QueryContextView { export class QueryContext implements QueryContextView {
private currentStack: StructureElement[] = []; private currentElementStack: StructureElement[] = [];
private currentLocked = false; private currentStructureStack: Structure[] = [];
readonly inputStructure: Structure; readonly inputStructure: Structure;
/** Current element */ /** Current element */
readonly element: StructureElement = StructureElement.create(); readonly element: StructureElement = StructureElement.create();
readonly currentStructure: Structure = void 0 as any; currentStructure: Structure = void 0 as any;
pushCurrentElement(): StructureElement { pushCurrentElement(): StructureElement {
this.currentStack[this.currentStack.length] = this.element; this.currentElementStack[this.currentElementStack.length] = this.element;
(this.element as StructureElement) = StructureElement.create(); (this.element as StructureElement) = StructureElement.create();
return this.element; return this.element;
} }
popCurrentElement() { popCurrentElement() {
(this.element as StructureElement) = this.currentStack.pop()!; (this.element as StructureElement) = this.currentElementStack.pop()!;
} }
lockCurrentStructure(structure: Structure) { pushCurrentStructure() {
if (this.currentLocked) throw new Error('Current structure already locked.'); if (this.currentStructure) this.currentStructureStack.push(this.currentStructure);
this.currentLocked = true;
(this.currentStructure as Structure) = structure;
} }
unlockCurrentStructure() { popCurrentStructure() {
this.currentLocked = false; if (this.currentStructureStack.length) (this.currentStructure as Structure) = this.currentStructureStack.pop()!;
(this.currentStructure as any) = void 0; else (this.currentStructure as Structure) = void 0 as any;
} }
constructor(structure: Structure) { constructor(structure: Structure) {
......
...@@ -3,3 +3,20 @@ ...@@ -3,3 +3,20 @@
* *
* @author David Sehnal <david.sehnal@gmail.com> * @author David Sehnal <david.sehnal@gmail.com>
*/ */
import { StructureQuery } from '../query';
import { StructureSelection } from '../selection';
export function merge(queries: ArrayLike<StructureQuery>): StructureQuery {
return ctx => {
const ret = StructureSelection.UniqueBuilder(ctx.inputStructure);
for (let i = 0; i < queries.length; i++) {
StructureSelection.forEach(queries[i](ctx), s => {
ret.add(s);
});
}
return ret.getSelection();
}
}
// TODO: intersect, distanceCluster
\ No newline at end of file
...@@ -4,37 +4,93 @@ ...@@ -4,37 +4,93 @@
* @author David Sehnal <david.sehnal@gmail.com> * @author David Sehnal <david.sehnal@gmail.com>
*/ */
import { SortedArray } from 'mol-data/int'; import { isSuperset } from 'mol-util/set';
import { Structure } from '../../structure'; import { Unit } from '../../structure';
import { QueryPredicate } from '../context'; import { QueryContext, QueryFn, QueryPredicate } from '../context';
import { StructureQuery } from '../query'; import { StructureQuery } from '../query';
import { StructureSelection } from '../selection'; import { StructureSelection } from '../selection';
import { structureAreIntersecting } from '../utils/structure';
export function pick(query: StructureQuery, pred: QueryPredicate): StructureQuery { export function pick(query: StructureQuery, pred: QueryPredicate): StructureQuery {
return ctx => { return ctx => {
const sel = query(ctx); const sel = query(ctx);
const ret = StructureSelection.LinearBuilder(ctx.inputStructure);
ctx.pushCurrentElement();
StructureSelection.forEach(sel, s => {
ctx.currentStructure = s;
if (pred(ctx)) ret.add(s);
});
ctx.popCurrentStructure();
return ret.getSelection();
};
}
if (StructureSelection.isSingleton(sel)) { export interface UnitTypeProperties { atomic?: QueryFn, coarse?: QueryFn }
const ret = StructureSelection.LinearBuilder(ctx.inputStructure);
for (const unit of ctx.inputStructure.units) { export function getCurrentStructureProperties(ctx: QueryContext, props: UnitTypeProperties, set: Set<any>) {
const { elements } = unit; const { units } = ctx.currentStructure;
for (let i = 0, _i = elements.length; i < _i; i++) { const l = ctx.pushCurrentElement();
// TODO: optimize this somehow???
const s = Structure.create([unit.getChild(SortedArray.ofSingleton(elements[i]))]); for (const unit of units) {
ctx.lockCurrentStructure(s); l.unit = unit;
if (pred(ctx)) ret.add(s); const elements = unit.elements;
ctx.unlockCurrentStructure();
} let fn;
} if (Unit.isAtomic(unit)) fn = props.atomic;
return ret.getSelection(); else fn = props.coarse;
} else { if (!fn) continue;
const ret = StructureSelection.LinearBuilder(ctx.inputStructure);
for (const s of sel.structures) { for (let j = 0, _j = elements.length; j < _j; j++) {
ctx.lockCurrentStructure(s); l.element = elements[j];
if (pred(ctx)) ret.add(s); set.add(fn(ctx));
ctx.unlockCurrentStructure();
}
return ret.getSelection();
} }
}
ctx.popCurrentElement();
return set;
}
function getSelectionProperties(ctx: QueryContext, query: StructureQuery, props: UnitTypeProperties) {
const set = new Set();
const sel = query(ctx);
ctx.pushCurrentElement();
StructureSelection.forEach(sel, s => {
ctx.currentStructure = s;
getCurrentStructureProperties(ctx, props, set);
});
ctx.popCurrentElement();
return set;
}
export function withSameAtomProperties(query: StructureQuery, propertySource: StructureQuery, props: UnitTypeProperties): StructureQuery {
return ctx => {
const sel = query(ctx);
const propSet = getSelectionProperties(ctx, propertySource, props);
const ret = StructureSelection.LinearBuilder(ctx.inputStructure);
ctx.pushCurrentStructure();
StructureSelection.forEach(sel, s => {
ctx.currentStructure = s;
const currentProps = getCurrentStructureProperties(ctx, props, new Set());
if (isSuperset(currentProps, propSet)) {
ret.add(s);
}
});
ctx.popCurrentStructure();
return ret.getSelection();
}; };
} }
export function areIntersectedBy(query: StructureQuery, by: StructureQuery): StructureQuery {
return ctx => {
const mask = StructureSelection.unionStructure(by(ctx));
const ret = StructureSelection.LinearBuilder(ctx.inputStructure);
StructureSelection.forEach(query(ctx), s => {
if (structureAreIntersecting(mask, s)) ret.add(s);
});
return ret.getSelection();
};
}
// TODO: within, isConnectedTo
\ No newline at end of file
...@@ -101,6 +101,24 @@ namespace StructureSelection { ...@@ -101,6 +101,24 @@ namespace StructureSelection {
export function LinearBuilder(structure: Structure): Builder { return new LinearBuilderImpl(structure); } export function LinearBuilder(structure: Structure): Builder { return new LinearBuilderImpl(structure); }
export function UniqueBuilder(structure: Structure): Builder { return new HashBuilderImpl(structure); } export function UniqueBuilder(structure: Structure): Builder { return new HashBuilderImpl(structure); }
export function forEach(sel: StructureSelection, fn: (s: Structure, i: number) => void) {
let idx = 0;
if (StructureSelection.isSingleton(sel)) {
for (const unit of sel.structure.units) {
const { elements } = unit;
for (let i = 0, _i = elements.length; i < _i; i++) {
// TODO: optimize this somehow???
const s = Structure.create([unit.getChild(SortedArray.ofSingleton(elements[i]))]);
fn(s, idx++);
}
}
} else {
for (const s of sel.structures) {
fn(s, idx++);
}
}
}
// TODO: spatial lookup // TODO: spatial lookup
} }
......
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