molstar
Version:
A comprehensive macromolecular library.
172 lines • 9.48 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 { __assign } from "tslib";
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, Mat4 } from '../../../mol-math/linear-algebra';
import { Mesh } from '../../../mol-geo/geometry/mesh/mesh';
import { MeshBuilder } from '../../../mol-geo/geometry/mesh/mesh-builder';
import { radToDeg, arcLength } from '../../../mol-math/misc';
import { Circle } from '../../../mol-geo/primitive/circle';
import { transformPrimitive } from '../../../mol-geo/primitive/primitive';
import { MarkerActions, MarkerAction } from '../../../mol-util/marker-action';
import { angleLabel } from '../../../mol-theme/label';
import { Sphere3D } from '../../../mol-math/geometry';
import { LociLabelTextParams } from './common';
var SharedParams = {
color: PD.Color(ColorNames.lightgreen),
arcScale: PD.Numeric(0.7, { min: 0.01, max: 1, step: 0.01 })
};
var LinesParams = __assign(__assign(__assign({}, Lines.Params), SharedParams), { lineSizeAttenuation: PD.Boolean(true), linesSize: PD.Numeric(0.04, { min: 0.01, max: 5, step: 0.01 }), dashLength: PD.Numeric(0.04, { min: 0.01, max: 0.2, step: 0.01 }) });
var VectorsParams = __assign({}, LinesParams);
var ArcParams = __assign({}, LinesParams);
var SectorParams = __assign(__assign(__assign({}, Mesh.Params), SharedParams), { ignoreLight: PD.Boolean(true), sectorOpacity: PD.Numeric(0.75, { min: 0, max: 1, step: 0.01 }) });
var AngleVisuals = {
'vectors': function (ctx, getParams) { return ShapeRepresentation(getVectorsShape, Lines.Utils, { modifyState: function (s) { return (__assign(__assign({}, s), { pickable: false })); } }); },
'arc': function (ctx, getParams) { return ShapeRepresentation(getArcShape, Lines.Utils, { modifyState: function (s) { return (__assign(__assign({}, s), { pickable: false })); } }); },
'sector': function (ctx, getParams) { return ShapeRepresentation(getSectorShape, Mesh.Utils, { modifyProps: function (p) { return (__assign(__assign({}, p), { alpha: p.sectorOpacity })); }, modifyState: function (s) { return (__assign(__assign({}, s), { markerActions: MarkerActions.Highlighting })); } }); },
'text': function (ctx, getParams) { return ShapeRepresentation(getTextShape, Text.Utils, { modifyState: function (s) { return (__assign(__assign({}, s), { markerActions: MarkerAction.None })); } }); },
};
export var AngleParams = __assign(__assign(__assign(__assign(__assign({}, VectorsParams), ArcParams), SectorParams), LociLabelTextParams), { visuals: PD.MultiSelect(['vectors', 'sector', 'text'], PD.objectToOptions(AngleVisuals)) });
//
function getAngleState() {
return {
sphereA: Sphere3D(),
sphereB: Sphere3D(),
sphereC: Sphere3D(),
arcDirA: Vec3(),
arcDirC: Vec3(),
arcNormal: Vec3(),
radius: 0,
angle: 0,
};
}
var tmpVec = Vec3();
var tmpMat = Mat4();
function setAngleState(triple, state, arcScale) {
var sphereA = state.sphereA, sphereB = state.sphereB, sphereC = state.sphereC;
var arcDirA = state.arcDirA, arcDirC = state.arcDirC, arcNormal = state.arcNormal;
var _a = triple.loci, lociA = _a[0], lociB = _a[1], lociC = _a[2];
Loci.getBoundingSphere(lociA, sphereA);
Loci.getBoundingSphere(lociB, sphereB);
Loci.getBoundingSphere(lociC, sphereC);
Vec3.sub(arcDirA, sphereA.center, sphereB.center);
Vec3.sub(arcDirC, sphereC.center, sphereB.center);
Vec3.cross(arcNormal, arcDirA, arcDirC);
var len = Math.min(Vec3.magnitude(arcDirA), Vec3.magnitude(arcDirC));
var radius = len * arcScale;
state.radius = radius;
state.angle = Vec3.angle(arcDirA, arcDirC);
return state;
}
function getCircle(state, segmentLength) {
var radius = state.radius, angle = state.angle;
var segments = segmentLength ? arcLength(angle, radius) / segmentLength : 32;
Mat4.targetTo(tmpMat, state.sphereB.center, state.sphereA.center, state.arcNormal);
Mat4.setTranslation(tmpMat, state.sphereB.center);
Mat4.mul(tmpMat, tmpMat, Mat4.rotY180);
var circle = Circle({ radius: radius, thetaLength: angle, segments: segments });
return transformPrimitive(circle, tmpMat);
}
var tmpState = getAngleState();
function getAngleName(data) {
return data.triples.length === 1 ? "Angle " + angleLabel(data.triples[0], { measureOnly: true }) : data.triples.length + " Angles";
}
//
function buildVectorsLines(data, props, lines) {
var builder = LinesBuilder.create(128, 64, lines);
for (var i = 0, il = data.triples.length; i < il; ++i) {
setAngleState(data.triples[i], tmpState, props.arcScale);
builder.addFixedLengthDashes(tmpState.sphereB.center, tmpState.sphereA.center, props.dashLength, i);
builder.addFixedLengthDashes(tmpState.sphereB.center, tmpState.sphereC.center, props.dashLength, i);
}
return builder.getLines();
}
function getVectorsShape(ctx, data, props, shape) {
var lines = buildVectorsLines(data, props, shape && shape.geometry);
var name = getAngleName(data);
return Shape.create(name, data, lines, function () { return props.color; }, function () { return props.linesSize; }, function () { return ''; });
}
//
function buildArcLines(data, props, lines) {
var builder = LinesBuilder.create(128, 64, lines);
for (var i = 0, il = data.triples.length; i < il; ++i) {
setAngleState(data.triples[i], tmpState, props.arcScale);
var circle = getCircle(tmpState, props.dashLength);
var indices = circle.indices, vertices = circle.vertices;
for (var j = 0, jl = indices.length; j < jl; j += 3) {
if (j % 2 === 1)
continue; // draw every other segment to get dashes
var start = indices[j] * 3;
var end = indices[j + 1] * 3;
var startX = vertices[start];
var startY = vertices[start + 1];
var startZ = vertices[start + 2];
var endX = vertices[end];
var endY = vertices[end + 1];
var endZ = vertices[end + 2];
builder.add(startX, startY, startZ, endX, endY, endZ, i);
}
}
return builder.getLines();
}
function getArcShape(ctx, data, props, shape) {
var lines = buildArcLines(data, props, shape && shape.geometry);
var name = getAngleName(data);
return Shape.create(name, data, lines, function () { return props.color; }, function () { return props.linesSize; }, function () { return ''; });
}
//
function buildSectorMesh(data, props, mesh) {
var state = MeshBuilder.createState(128, 64, mesh);
for (var i = 0, il = data.triples.length; i < il; ++i) {
setAngleState(data.triples[i], tmpState, props.arcScale);
var circle = getCircle(tmpState);
state.currentGroup = i;
MeshBuilder.addPrimitive(state, Mat4.id, circle);
MeshBuilder.addPrimitiveFlipped(state, Mat4.id, circle);
}
return MeshBuilder.getMesh(state);
}
function getSectorShape(ctx, data, props, shape) {
var mesh = buildSectorMesh(data, props, shape && shape.geometry);
var name = getAngleName(data);
var getLabel = function (groupId) { return angleLabel(data.triples[groupId]); };
return Shape.create(name, data, mesh, function () { return props.color; }, function () { return 1; }, getLabel);
}
//
function buildText(data, props, text) {
var builder = TextBuilder.create(props, 128, 64, text);
for (var i = 0, il = data.triples.length; i < il; ++i) {
setAngleState(data.triples[i], tmpState, props.arcScale);
Vec3.add(tmpVec, tmpState.arcDirA, tmpState.arcDirC);
Vec3.setMagnitude(tmpVec, tmpVec, tmpState.radius);
Vec3.add(tmpVec, tmpState.sphereB.center, tmpVec);
var angle = radToDeg(tmpState.angle).toFixed(2);
var label = props.customText || angle + "\u00B0";
var radius = Math.max(2, tmpState.sphereA.radius, tmpState.sphereB.radius, tmpState.sphereC.radius);
var scale = radius / 2;
builder.add(label, tmpVec[0], tmpVec[1], tmpVec[2], 0.1, scale, i);
}
return builder.getText();
}
function getTextShape(ctx, data, props, shape) {
var text = buildText(data, props, shape && shape.geometry);
var name = getAngleName(data);
var getLabel = function (groupId) { return angleLabel(data.triples[groupId]); };
return Shape.create(name, data, text, function () { return props.textColor; }, function () { return props.textSize; }, getLabel);
}
export function AngleRepresentation(ctx, getParams) {
return Representation.createMulti('Angle', ctx, getParams, Representation.StateBuilder, AngleVisuals);
}
//# sourceMappingURL=angle.js.map