UNPKG

molstar

Version:

A comprehensive macromolecular library.

196 lines (195 loc) 9.95 kB
"use strict"; /** * Copyright (c) 2019-2020 mol* contributors, licensed under MIT, See LICENSE file for more info. * * @author Alexander Rose <alexander.rose@weirdbyte.de> */ Object.defineProperty(exports, "__esModule", { value: true }); exports.AngleParams = void 0; exports.AngleRepresentation = AngleRepresentation; const loci_1 = require("../../../mol-model/loci"); const lines_1 = require("../../../mol-geo/geometry/lines/lines"); const text_1 = require("../../../mol-geo/geometry/text/text"); const param_definition_1 = require("../../../mol-util/param-definition"); const names_1 = require("../../../mol-util/color/names"); const representation_1 = require("../representation"); const representation_2 = require("../../representation"); const shape_1 = require("../../../mol-model/shape"); const lines_builder_1 = require("../../../mol-geo/geometry/lines/lines-builder"); const text_builder_1 = require("../../../mol-geo/geometry/text/text-builder"); const linear_algebra_1 = require("../../../mol-math/linear-algebra"); const mesh_1 = require("../../../mol-geo/geometry/mesh/mesh"); const mesh_builder_1 = require("../../../mol-geo/geometry/mesh/mesh-builder"); const misc_1 = require("../../../mol-math/misc"); const circle_1 = require("../../../mol-geo/primitive/circle"); const primitive_1 = require("../../../mol-geo/primitive/primitive"); const marker_action_1 = require("../../../mol-util/marker-action"); const label_1 = require("../../../mol-theme/label"); const geometry_1 = require("../../../mol-math/geometry"); const common_1 = require("./common"); const SharedParams = { color: param_definition_1.ParamDefinition.Color(names_1.ColorNames.lightgreen), arcScale: param_definition_1.ParamDefinition.Numeric(0.7, { min: 0.01, max: 1, step: 0.01 }) }; const LinesParams = { ...lines_1.Lines.Params, ...SharedParams, lineSizeAttenuation: param_definition_1.ParamDefinition.Boolean(true), linesSize: param_definition_1.ParamDefinition.Numeric(0.04, { min: 0.01, max: 5, step: 0.01 }), dashLength: param_definition_1.ParamDefinition.Numeric(0.04, { min: 0.01, max: 0.2, step: 0.01 }), }; const VectorsParams = { ...LinesParams }; const ArcParams = { ...LinesParams }; const SectorParams = { ...mesh_1.Mesh.Params, ...SharedParams, ignoreLight: param_definition_1.ParamDefinition.Boolean(true), sectorOpacity: param_definition_1.ParamDefinition.Numeric(0.75, { min: 0, max: 1, step: 0.01 }), }; const AngleVisuals = { 'vectors': (ctx, getParams) => (0, representation_1.ShapeRepresentation)(getVectorsShape, lines_1.Lines.Utils, { modifyState: s => ({ ...s, pickable: false }) }), 'arc': (ctx, getParams) => (0, representation_1.ShapeRepresentation)(getArcShape, lines_1.Lines.Utils, { modifyState: s => ({ ...s, pickable: false }) }), 'sector': (ctx, getParams) => (0, representation_1.ShapeRepresentation)(getSectorShape, mesh_1.Mesh.Utils, { modifyProps: p => ({ ...p, alpha: p.sectorOpacity }), modifyState: s => ({ ...s, markerActions: marker_action_1.MarkerActions.Highlighting }) }), 'text': (ctx, getParams) => (0, representation_1.ShapeRepresentation)(getTextShape, text_1.Text.Utils, { modifyState: s => ({ ...s, markerActions: marker_action_1.MarkerAction.None }) }), }; exports.AngleParams = { ...VectorsParams, ...ArcParams, ...SectorParams, ...common_1.LociLabelTextParams, visuals: param_definition_1.ParamDefinition.MultiSelect(['vectors', 'sector', 'text'], param_definition_1.ParamDefinition.objectToOptions(AngleVisuals)), }; // function getAngleState() { return { sphereA: (0, geometry_1.Sphere3D)(), sphereB: (0, geometry_1.Sphere3D)(), sphereC: (0, geometry_1.Sphere3D)(), arcDirA: (0, linear_algebra_1.Vec3)(), arcDirC: (0, linear_algebra_1.Vec3)(), arcNormal: (0, linear_algebra_1.Vec3)(), radius: 0, angle: 0, }; } const tmpVec = (0, linear_algebra_1.Vec3)(); const tmpMat = (0, linear_algebra_1.Mat4)(); function setAngleState(triple, state, arcScale) { const { sphereA, sphereB, sphereC } = state; const { arcDirA, arcDirC, arcNormal } = state; const [lociA, lociB, lociC] = triple.loci; loci_1.Loci.getBoundingSphere(lociA, sphereA); loci_1.Loci.getBoundingSphere(lociB, sphereB); loci_1.Loci.getBoundingSphere(lociC, sphereC); linear_algebra_1.Vec3.sub(arcDirA, sphereA.center, sphereB.center); linear_algebra_1.Vec3.sub(arcDirC, sphereC.center, sphereB.center); linear_algebra_1.Vec3.cross(arcNormal, arcDirA, arcDirC); const len = Math.min(linear_algebra_1.Vec3.magnitude(arcDirA), linear_algebra_1.Vec3.magnitude(arcDirC)); const radius = len * arcScale; state.radius = radius; state.angle = linear_algebra_1.Vec3.angle(arcDirA, arcDirC); return state; } function getCircle(state, segmentLength) { const { radius, angle } = state; const segments = segmentLength ? (0, misc_1.arcLength)(angle, radius) / segmentLength : 32; linear_algebra_1.Mat4.targetTo(tmpMat, state.sphereB.center, state.sphereA.center, state.arcNormal); linear_algebra_1.Mat4.setTranslation(tmpMat, state.sphereB.center); linear_algebra_1.Mat4.mul(tmpMat, tmpMat, linear_algebra_1.Mat4.rotY180); const circle = (0, circle_1.Circle)({ radius, thetaLength: angle, segments }); return (0, primitive_1.transformPrimitive)(circle, tmpMat); } const tmpState = getAngleState(); function getAngleName(data) { return data.triples.length === 1 ? `Angle ${(0, label_1.angleLabel)(data.triples[0], { measureOnly: true })}` : `${data.triples.length} Angles`; } // function buildVectorsLines(data, props, lines) { const builder = lines_builder_1.LinesBuilder.create(128, 64, lines); for (let 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) { const lines = buildVectorsLines(data, props, shape && shape.geometry); const name = getAngleName(data); return shape_1.Shape.create(name, data, lines, () => props.color, () => props.linesSize, () => ''); } // function buildArcLines(data, props, lines) { const builder = lines_builder_1.LinesBuilder.create(128, 64, lines); for (let i = 0, il = data.triples.length; i < il; ++i) { setAngleState(data.triples[i], tmpState, props.arcScale); const circle = getCircle(tmpState, props.dashLength); const { indices, vertices } = circle; for (let j = 0, jl = indices.length; j < jl; j += 3) { if (j % 2 === 1) continue; // draw every other segment to get dashes const start = indices[j] * 3; const end = indices[j + 1] * 3; const startX = vertices[start]; const startY = vertices[start + 1]; const startZ = vertices[start + 2]; const endX = vertices[end]; const endY = vertices[end + 1]; const endZ = vertices[end + 2]; builder.add(startX, startY, startZ, endX, endY, endZ, i); } } return builder.getLines(); } function getArcShape(ctx, data, props, shape) { const lines = buildArcLines(data, props, shape && shape.geometry); const name = getAngleName(data); return shape_1.Shape.create(name, data, lines, () => props.color, () => props.linesSize, () => ''); } // function buildSectorMesh(data, props, mesh) { const state = mesh_builder_1.MeshBuilder.createState(128, 64, mesh); for (let i = 0, il = data.triples.length; i < il; ++i) { setAngleState(data.triples[i], tmpState, props.arcScale); const circle = getCircle(tmpState); state.currentGroup = i; mesh_builder_1.MeshBuilder.addPrimitive(state, linear_algebra_1.Mat4.id, circle); mesh_builder_1.MeshBuilder.addPrimitiveFlipped(state, linear_algebra_1.Mat4.id, circle); } return mesh_builder_1.MeshBuilder.getMesh(state); } function getSectorShape(ctx, data, props, shape) { const mesh = buildSectorMesh(data, props, shape && shape.geometry); const name = getAngleName(data); const getLabel = (groupId) => (0, label_1.angleLabel)(data.triples[groupId]); return shape_1.Shape.create(name, data, mesh, () => props.color, () => 1, getLabel); } // function buildText(data, props, text) { const builder = text_builder_1.TextBuilder.create(props, 128, 64, text); for (let i = 0, il = data.triples.length; i < il; ++i) { setAngleState(data.triples[i], tmpState, props.arcScale); linear_algebra_1.Vec3.add(tmpVec, tmpState.arcDirA, tmpState.arcDirC); linear_algebra_1.Vec3.setMagnitude(tmpVec, tmpVec, tmpState.radius); linear_algebra_1.Vec3.add(tmpVec, tmpState.sphereB.center, tmpVec); const angle = (0, misc_1.radToDeg)(tmpState.angle).toFixed(2); const label = props.customText || `${angle}\u00B0`; const radius = Math.max(2, tmpState.sphereA.radius, tmpState.sphereB.radius, tmpState.sphereC.radius); const 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) { const text = buildText(data, props, shape && shape.geometry); const name = getAngleName(data); const getLabel = (groupId) => (0, label_1.angleLabel)(data.triples[groupId]); return shape_1.Shape.create(name, data, text, () => props.textColor, () => props.textSize, getLabel); } function AngleRepresentation(ctx, getParams) { return representation_2.Representation.createMulti('Angle', ctx, getParams, representation_2.Representation.StateBuilder, AngleVisuals); }