molstar
Version:
A comprehensive macromolecular library.
180 lines • 8.73 kB
JavaScript
/**
* Copyright (c) 2020 mol* contributors, licensed under MIT, See LICENSE file for more info.
*
* @author Alexander Rose <alexander.rose@weirdbyte.de>
*/
import { __assign } from "tslib";
import { Scene } from '../../mol-gl/scene';
import { MeshBuilder } from '../../mol-geo/geometry/mesh/mesh-builder';
import { Vec3, Mat4 } from '../../mol-math/linear-algebra';
import { addSphere } from '../../mol-geo/geometry/mesh/builder/sphere';
import { Mesh } from '../../mol-geo/geometry/mesh/mesh';
import { ColorNames } from '../../mol-util/color/names';
import { addCylinder } from '../../mol-geo/geometry/mesh/builder/cylinder';
import { ValueCell } from '../../mol-util';
import { Sphere3D } from '../../mol-math/geometry';
import { ParamDefinition as PD } from '../../mol-util/param-definition';
import produce from 'immer';
import { Shape } from '../../mol-model/shape';
import { DataLoci, EmptyLoci } from '../../mol-model/loci';
import { MarkerActions } from '../../mol-util/marker-action';
import { Visual } from '../../mol-repr/visual';
import { Interval } from '../../mol-data/int';
var HandleParams = __assign(__assign({}, Mesh.Params), { alpha: __assign(__assign({}, Mesh.Params.alpha), { defaultValue: 1 }), ignoreLight: __assign(__assign({}, Mesh.Params.ignoreLight), { defaultValue: true }), colorX: PD.Color(ColorNames.red, { isEssential: true }), colorY: PD.Color(ColorNames.green, { isEssential: true }), colorZ: PD.Color(ColorNames.blue, { isEssential: true }), scale: PD.Numeric(0.33, { min: 0.1, max: 2, step: 0.1 }, { isEssential: true }) });
export var HandleHelperParams = {
handle: PD.MappedStatic('off', {
on: PD.Group(HandleParams),
off: PD.Group({})
}, { cycle: true, description: 'Show handle tool' }),
};
var HandleHelper = /** @class */ (function () {
function HandleHelper(webgl, props) {
var _this = this;
if (props === void 0) { props = {}; }
this.webgl = webgl;
this.props = {
handle: { name: 'off', params: {} }
};
this._transform = Mat4();
this.eachGroup = function (loci, apply) {
if (!_this.renderObject)
return false;
if (!isHandleLoci(loci))
return false;
var changed = false;
var groupCount = _this.renderObject.values.uGroupCount.ref.value;
var elements = loci.elements;
for (var _i = 0, elements_1 = elements; _i < elements_1.length; _i++) {
var _a = elements_1[_i], groupId = _a.groupId, instanceId = _a.instanceId;
var idx = instanceId * groupCount + groupId;
if (apply(Interval.ofSingleton(idx)))
changed = true;
}
return changed;
};
this.scene = Scene.create(webgl);
this.setProps(props);
}
HandleHelper.prototype.getBoundingSphere = function (out, instanceId) {
if (this.renderObject) {
Sphere3D.copy(out, this.renderObject.values.invariantBoundingSphere.ref.value);
Mat4.fromArray(this._transform, this.renderObject.values.aTransform.ref.value, instanceId * 16);
Sphere3D.transform(out, out, this._transform);
}
return out;
};
HandleHelper.prototype.setProps = function (props) {
var _this = this;
this.props = produce(this.props, function (p) {
if (props.handle !== undefined) {
p.handle.name = props.handle.name;
if (props.handle.name === 'on') {
_this.scene.clear();
var params = __assign(__assign({}, props.handle.params), { scale: props.handle.params.scale * _this.webgl.pixelRatio });
_this.renderObject = createHandleRenderObject(params);
_this.renderObject.state.noClip = true;
_this.scene.add(_this.renderObject);
_this.scene.commit();
p.handle.params = __assign({}, props.handle.params);
}
}
});
};
Object.defineProperty(HandleHelper.prototype, "isEnabled", {
get: function () {
return this.props.handle.name === 'on';
},
enumerable: false,
configurable: true
});
// TODO could be a lists of position/rotation if we want to show more than one handle tool,
// they would be distingishable by their instanceId
HandleHelper.prototype.update = function (camera, position, rotation) {
if (!this.renderObject)
return;
Mat4.setTranslation(this.renderObject.values.aTransform.ref.value, position);
Mat4.fromMat3(this.renderObject.values.aTransform.ref.value, rotation);
// TODO make invariant to camera scaling by adjusting renderObject transform
ValueCell.update(this.renderObject.values.aTransform, this.renderObject.values.aTransform.ref.value);
this.scene.update([this.renderObject], true);
};
HandleHelper.prototype.getLoci = function (pickingId) {
var objectId = pickingId.objectId, groupId = pickingId.groupId, instanceId = pickingId.instanceId;
if (!this.renderObject || objectId !== this.renderObject.id)
return EmptyLoci;
return HandleLoci(this, groupId, instanceId);
};
HandleHelper.prototype.mark = function (loci, action) {
if (!MarkerActions.is(MarkerActions.Highlighting, action))
return false;
if (!isHandleLoci(loci))
return false;
if (loci.data !== this)
return false;
return Visual.mark(this.renderObject, loci, action, this.eachGroup);
};
return HandleHelper;
}());
export { HandleHelper };
function createHandleMesh(scale, mesh) {
var state = MeshBuilder.createState(512, 256, mesh);
var radius = 0.05 * scale;
var x = Vec3.scale(Vec3(), Vec3.unitX, scale);
var y = Vec3.scale(Vec3(), Vec3.unitY, scale);
var z = Vec3.scale(Vec3(), Vec3.unitZ, scale);
var cylinderProps = { radiusTop: radius, radiusBottom: radius, radialSegments: 32 };
state.currentGroup = HandleGroup.TranslateScreenXY;
addSphere(state, Vec3.origin, radius * 3, 2);
state.currentGroup = HandleGroup.TranslateObjectX;
addSphere(state, x, radius, 2);
addCylinder(state, Vec3.origin, x, 1, cylinderProps);
state.currentGroup = HandleGroup.TranslateObjectY;
addSphere(state, y, radius, 2);
addCylinder(state, Vec3.origin, y, 1, cylinderProps);
state.currentGroup = HandleGroup.TranslateObjectZ;
addSphere(state, z, radius, 2);
addCylinder(state, Vec3.origin, z, 1, cylinderProps);
// TODO add more helper geometries for the other HandleGroup options
// TODO add props to create subset of geometries
return MeshBuilder.getMesh(state);
}
export var HandleGroup = {
None: 0,
TranslateScreenXY: 1,
// TranslateScreenZ: 2,
TranslateObjectX: 3,
TranslateObjectY: 4,
TranslateObjectZ: 5,
// TranslateObjectXY: 6,
// TranslateObjectXZ: 7,
// TranslateObjectYZ: 8,
// RotateScreenZ: 9,
// RotateObjectX: 10,
// RotateObjectY: 11,
// RotateObjectZ: 12,
};
function HandleLoci(handleHelper, groupId, instanceId) {
return DataLoci('handle', handleHelper, [{ groupId: groupId, instanceId: instanceId }], function (boundingSphere) { return handleHelper.getBoundingSphere(boundingSphere, instanceId); }, function () { return "Handle Helper | Group Id " + groupId + " | Instance Id " + instanceId; });
}
export function isHandleLoci(x) {
return x.kind === 'data-loci' && x.tag === 'handle';
}
function getHandleShape(props, shape) {
var scale = 10 * props.scale;
var mesh = createHandleMesh(scale, shape === null || shape === void 0 ? void 0 : shape.geometry);
mesh.setBoundingSphere(Sphere3D.create(Vec3.create(scale / 2, scale / 2, scale / 2), scale + scale / 4));
var getColor = function (groupId) {
switch (groupId) {
case HandleGroup.TranslateObjectX: return props.colorX;
case HandleGroup.TranslateObjectY: return props.colorY;
case HandleGroup.TranslateObjectZ: return props.colorZ;
default: return ColorNames.grey;
}
};
return Shape.create('handle', {}, mesh, getColor, function () { return 1; }, function () { return ''; });
}
function createHandleRenderObject(props) {
var shape = getHandleShape(props);
return Shape.createRenderObject(shape, props);
}
//# sourceMappingURL=handle-helper.js.map