molstar
Version:
A comprehensive macromolecular library.
105 lines (104 loc) • 4.65 kB
JavaScript
/**
* Copyright (c) 2019-2020 mol* contributors, licensed under MIT, See LICENSE file for more info.
*
* @author Alexander Rose <alexander.rose@weirdbyte.de>
*/
import { Loci } from '../../../mol-model/loci';
import { Lines } from '../../../mol-geo/geometry/lines/lines';
import { Text } from '../../../mol-geo/geometry/text/text';
import { ParamDefinition as PD } from '../../../mol-util/param-definition';
import { ColorNames } from '../../../mol-util/color/names';
import { ShapeRepresentation } from '../representation';
import { Representation } from '../../representation';
import { Shape } from '../../../mol-model/shape';
import { LinesBuilder } from '../../../mol-geo/geometry/lines/lines-builder';
import { TextBuilder } from '../../../mol-geo/geometry/text/text-builder';
import { Vec3 } from '../../../mol-math/linear-algebra';
import { MarkerActions, MarkerAction } from '../../../mol-util/marker-action';
import { distanceLabel } from '../../../mol-theme/label';
import { LociLabelTextParams } from './common';
import { Sphere3D } from '../../../mol-math/geometry';
const SharedParams = {
unitLabel: PD.Text('\u212B', { isEssential: true })
};
const LineParams = {
...Lines.Params,
...SharedParams,
lineSizeAttenuation: PD.Boolean(true),
linesColor: PD.Color(ColorNames.lightgreen, { isEssential: true }),
linesSize: PD.Numeric(0.075, { min: 0.01, max: 5, step: 0.01 }),
dashLength: PD.Numeric(0.2, { min: 0.01, max: 0.2, step: 0.01 }),
};
const TextParams = {
...LociLabelTextParams,
...SharedParams,
};
const DistanceVisuals = {
'lines': (ctx, getParams) => ShapeRepresentation(getLinesShape, Lines.Utils, { modifyState: s => ({ ...s, markerActions: MarkerActions.Highlighting }) }),
'text': (ctx, getParams) => ShapeRepresentation(getTextShape, Text.Utils, { modifyState: s => ({ ...s, markerActions: MarkerAction.None }) }),
};
export const DistanceParams = {
...LineParams,
...TextParams,
visuals: PD.MultiSelect(['lines', 'text'], PD.objectToOptions(DistanceVisuals)),
};
//
function getDistanceState() {
return {
sphereA: Sphere3D(),
sphereB: Sphere3D(),
center: Vec3(),
distance: 0,
};
}
function setDistanceState(pair, state) {
const { sphereA, sphereB, center } = state;
const [lociA, lociB] = pair.loci;
Loci.getBoundingSphere(lociA, sphereA);
Loci.getBoundingSphere(lociB, sphereB);
Vec3.add(center, sphereA.center, sphereB.center);
Vec3.scale(center, center, 0.5);
state.distance = Vec3.distance(sphereA.center, sphereB.center);
return state;
}
const tmpState = getDistanceState();
function getDistanceName(data, unitLabel) {
return data.pairs.length === 1 ? `Distance ${distanceLabel(data.pairs[0], { unitLabel, measureOnly: true })}` : `${data.pairs.length} Distances`;
}
//
function buildLines(data, props, lines) {
const builder = LinesBuilder.create(128, 64, lines);
for (let i = 0, il = data.pairs.length; i < il; ++i) {
setDistanceState(data.pairs[i], tmpState);
builder.addFixedLengthDashes(tmpState.sphereA.center, tmpState.sphereB.center, props.dashLength, i);
}
return builder.getLines();
}
function getLinesShape(ctx, data, props, shape) {
const lines = buildLines(data, props, shape && shape.geometry);
const name = getDistanceName(data, props.unitLabel);
const getLabel = (groupId) => distanceLabel(data.pairs[groupId], props);
return Shape.create(name, data, lines, () => props.linesColor, () => props.linesSize, getLabel);
}
//
function buildText(data, props, text) {
const builder = TextBuilder.create(props, 128, 64, text);
for (let i = 0, il = data.pairs.length; i < il; ++i) {
setDistanceState(data.pairs[i], tmpState);
const { center, distance, sphereA, sphereB } = tmpState;
const label = props.customText || `${distance.toFixed(2)} ${props.unitLabel}`;
const radius = Math.max(2, sphereA.radius, sphereB.radius);
const scale = radius / 2;
builder.add(label, center[0], center[1], center[2], 1, scale, i);
}
return builder.getText();
}
function getTextShape(ctx, data, props, shape) {
const text = buildText(data, props, shape && shape.geometry);
const name = getDistanceName(data, props.unitLabel);
const getLabel = (groupId) => distanceLabel(data.pairs[groupId], props);
return Shape.create(name, data, text, () => props.textColor, () => props.textSize, getLabel);
}
export function DistanceRepresentation(ctx, getParams) {
return Representation.createMulti('Distance', ctx, getParams, Representation.StateBuilder, DistanceVisuals);
}