molstar
Version:
A comprehensive macromolecular library.
295 lines • 15.1 kB
JavaScript
"use strict";
/**
* Copyright (c) 2019-2020 mol* contributors, licensed under MIT, See LICENSE file for more info.
*
* @author Schäfer, Marco <marco.schaefer@uni-tuebingen.de>
* @author Alexander Rose <alexander.rose@weirdbyte.de>
*/
Object.defineProperty(exports, "__esModule", { value: true });
exports.shapeFromPly = exports.PlyShapeParams = void 0;
var tslib_1 = require("tslib");
var mol_task_1 = require("../../mol-task");
var color_1 = require("../../mol-util/color");
var mesh_builder_1 = require("../../mol-geo/geometry/mesh/mesh-builder");
var mesh_1 = require("../../mol-geo/geometry/mesh/mesh");
var shape_1 = require("../../mol-model/shape");
var util_1 = require("../../mol-data/util");
var array_1 = require("../../mol-util/array");
var db_1 = require("../../mol-data/db");
var param_definition_1 = require("../../mol-util/param-definition");
var names_1 = require("../../mol-util/color/names");
var object_1 = require("../../mol-util/object");
var string_1 = require("../../mol-util/string");
// TODO support 'edge' element, see https://www.mathworks.com/help/vision/ug/the-ply-format.html
// TODO support missing face element
function createPlyShapeParams(plyFile) {
var vertex = plyFile && plyFile.getElement('vertex');
var material = plyFile && plyFile.getElement('material');
var defaultValues = { group: '', vRed: '', vGreen: '', vBlue: '', mRed: '', mGreen: '', mBlue: '' };
var groupOptions = [['', '']];
var colorOptions = [['', '']];
if (vertex) {
for (var i = 0, il = vertex.propertyNames.length; i < il; ++i) {
var name_1 = vertex.propertyNames[i];
var type = vertex.propertyTypes[i];
if (type === 'uchar' || type === 'uint8' ||
type === 'ushort' || type === 'uint16' ||
type === 'uint' || type === 'uint32' ||
type === 'int')
groupOptions.push([name_1, name_1]);
if (type === 'uchar' || type === 'uint8')
colorOptions.push([name_1, name_1]);
}
// TODO hardcoded as convenience for data provided by MegaMol
if (vertex.propertyNames.includes('atomid'))
defaultValues.group = 'atomid';
else if (vertex.propertyNames.includes('material_index'))
defaultValues.group = 'material_index';
if (vertex.propertyNames.includes('red'))
defaultValues.vRed = 'red';
if (vertex.propertyNames.includes('green'))
defaultValues.vGreen = 'green';
if (vertex.propertyNames.includes('blue'))
defaultValues.vBlue = 'blue';
}
var materialOptions = [['', '']];
if (material) {
for (var i = 0, il = material.propertyNames.length; i < il; ++i) {
var name_2 = material.propertyNames[i];
var type = material.propertyTypes[i];
if (type === 'uchar' || type === 'uint8')
materialOptions.push([name_2, name_2]);
}
if (material.propertyNames.includes('red'))
defaultValues.mRed = 'red';
if (material.propertyNames.includes('green'))
defaultValues.mGreen = 'green';
if (material.propertyNames.includes('blue'))
defaultValues.mBlue = 'blue';
}
var defaultColoring = defaultValues.vRed && defaultValues.vGreen && defaultValues.vBlue ? 'vertex' :
defaultValues.mRed && defaultValues.mGreen && defaultValues.mBlue ? 'material' : 'uniform';
return (0, tslib_1.__assign)((0, tslib_1.__assign)({}, mesh_1.Mesh.Params), { coloring: param_definition_1.ParamDefinition.MappedStatic(defaultColoring, {
vertex: param_definition_1.ParamDefinition.Group({
red: param_definition_1.ParamDefinition.Select(defaultValues.vRed, colorOptions, { label: 'Red Property' }),
green: param_definition_1.ParamDefinition.Select(defaultValues.vGreen, colorOptions, { label: 'Green Property' }),
blue: param_definition_1.ParamDefinition.Select(defaultValues.vBlue, colorOptions, { label: 'Blue Property' }),
}, { isFlat: true }),
material: param_definition_1.ParamDefinition.Group({
red: param_definition_1.ParamDefinition.Select(defaultValues.mRed, materialOptions, { label: 'Red Property' }),
green: param_definition_1.ParamDefinition.Select(defaultValues.mGreen, materialOptions, { label: 'Green Property' }),
blue: param_definition_1.ParamDefinition.Select(defaultValues.mBlue, materialOptions, { label: 'Blue Property' }),
}, { isFlat: true }),
uniform: param_definition_1.ParamDefinition.Group({
color: param_definition_1.ParamDefinition.Color(names_1.ColorNames.grey)
}, { isFlat: true })
}), grouping: param_definition_1.ParamDefinition.MappedStatic(defaultValues.group ? 'vertex' : 'none', {
vertex: param_definition_1.ParamDefinition.Group({
group: param_definition_1.ParamDefinition.Select(defaultValues.group, groupOptions, { label: 'Group Property' }),
}, { isFlat: true }),
none: param_definition_1.ParamDefinition.Group({})
}) });
}
exports.PlyShapeParams = createPlyShapeParams();
function addVerticesRange(begI, endI, state, vertex, groupIds) {
var vertices = state.vertices, normals = state.normals, groups = state.groups;
var x = vertex.getProperty('x');
var y = vertex.getProperty('y');
var z = vertex.getProperty('z');
if (!x || !y || !z)
throw new Error('missing coordinate properties');
var nx = vertex.getProperty('nx');
var ny = vertex.getProperty('ny');
var nz = vertex.getProperty('nz');
var hasNormals = !!nx && !!ny && !!nz;
for (var i = begI; i < endI; ++i) {
util_1.ChunkedArray.add3(vertices, x.value(i), y.value(i), z.value(i));
if (hasNormals)
util_1.ChunkedArray.add3(normals, nx.value(i), ny.value(i), nz.value(i));
util_1.ChunkedArray.add(groups, groupIds[i]);
}
}
function addFacesRange(begI, endI, state, face) {
var indices = state.indices;
for (var i = begI; i < endI; ++i) {
var _a = face.value(i), entries = _a.entries, count = _a.count;
if (count === 3) {
// triangle
util_1.ChunkedArray.add3(indices, entries[0], entries[1], entries[2]);
}
else if (count === 4) {
// quadrilateral
util_1.ChunkedArray.add3(indices, entries[2], entries[1], entries[0]);
util_1.ChunkedArray.add3(indices, entries[2], entries[0], entries[3]);
}
}
}
function getMesh(ctx, vertex, face, groupIds, mesh) {
return (0, tslib_1.__awaiter)(this, void 0, void 0, function () {
var builderState, x, y, z, nx, ny, nz, hasNormals, updateChunk, i, il, i, il, m;
return (0, tslib_1.__generator)(this, function (_a) {
switch (_a.label) {
case 0:
builderState = mesh_builder_1.MeshBuilder.createState(vertex.rowCount, vertex.rowCount / 4, mesh);
x = vertex.getProperty('x');
y = vertex.getProperty('y');
z = vertex.getProperty('z');
if (!x || !y || !z)
throw new Error('missing coordinate properties');
nx = vertex.getProperty('nx');
ny = vertex.getProperty('ny');
nz = vertex.getProperty('nz');
hasNormals = !!nx && !!ny && !!nz;
updateChunk = 100000;
i = 0, il = vertex.rowCount;
_a.label = 1;
case 1:
if (!(i < il)) return [3 /*break*/, 4];
addVerticesRange(i, Math.min(i + updateChunk, il), builderState, vertex, groupIds);
if (!ctx.shouldUpdate) return [3 /*break*/, 3];
return [4 /*yield*/, ctx.update({ message: 'adding ply mesh vertices', current: i, max: il })];
case 2:
_a.sent();
_a.label = 3;
case 3:
i += updateChunk;
return [3 /*break*/, 1];
case 4:
i = 0, il = face.rowCount;
_a.label = 5;
case 5:
if (!(i < il)) return [3 /*break*/, 8];
addFacesRange(i, Math.min(i + updateChunk, il), builderState, face);
if (!ctx.shouldUpdate) return [3 /*break*/, 7];
return [4 /*yield*/, ctx.update({ message: 'adding ply mesh faces', current: i, max: il })];
case 6:
_a.sent();
_a.label = 7;
case 7:
i += updateChunk;
return [3 /*break*/, 5];
case 8:
m = mesh_builder_1.MeshBuilder.getMesh(builderState);
if (!hasNormals)
mesh_1.Mesh.computeNormals(m);
return [2 /*return*/, m];
}
});
});
}
var int = db_1.Column.Schema.int;
function getGrouping(vertex, props) {
var grouping = props.grouping;
var rowCount = vertex.rowCount;
var column = grouping.name === 'vertex' ? vertex.getProperty(grouping.params.group) : undefined;
var label = grouping.name === 'vertex' ? (0, string_1.stringToWords)(grouping.params.group) : 'Vertex';
var ids = column ? column.toArray({ array: Uint32Array }) : (0, array_1.fillSerial)(new Uint32Array(rowCount));
var maxId = column ? (0, array_1.arrayMax)(ids) : rowCount - 1; // assumes uint ids
var map = new Uint32Array(maxId + 1);
for (var i = 0, il = ids.length; i < il; ++i)
map[ids[i]] = i;
return { ids: ids, map: map, label: label };
}
function getColoring(vertex, material, props) {
var coloring = props.coloring;
var rowCount = vertex.rowCount;
var red, green, blue;
if (coloring.name === 'vertex') {
red = vertex.getProperty(coloring.params.red) || db_1.Column.ofConst(127, rowCount, int);
green = vertex.getProperty(coloring.params.green) || db_1.Column.ofConst(127, rowCount, int);
blue = vertex.getProperty(coloring.params.blue) || db_1.Column.ofConst(127, rowCount, int);
}
else if (coloring.name === 'material') {
red = (material && material.getProperty(coloring.params.red)) || db_1.Column.ofConst(127, rowCount, int);
green = (material && material.getProperty(coloring.params.green)) || db_1.Column.ofConst(127, rowCount, int);
blue = (material && material.getProperty(coloring.params.blue)) || db_1.Column.ofConst(127, rowCount, int);
}
else {
var _a = color_1.Color.toRgb(coloring.params.color), r = _a[0], g = _a[1], b = _a[2];
red = db_1.Column.ofConst(r, rowCount, int);
green = db_1.Column.ofConst(g, rowCount, int);
blue = db_1.Column.ofConst(b, rowCount, int);
}
return { kind: coloring.name, red: red, green: green, blue: blue };
}
function createShape(plyFile, mesh, coloring, grouping) {
var kind = coloring.kind, red = coloring.red, green = coloring.green, blue = coloring.blue;
var ids = grouping.ids, map = grouping.map, label = grouping.label;
return shape_1.Shape.create('ply-mesh', plyFile, mesh, function (groupId) {
var idx = kind === 'material' ? groupId : map[groupId];
return color_1.Color.fromRgb(red.value(idx), green.value(idx), blue.value(idx));
}, function () { return 1; }, // size: constant
function (groupId) {
return label + " " + ids[groupId];
});
}
function makeShapeGetter() {
var _this = this;
var _plyFile;
var _props;
var _shape;
var _mesh;
var _coloring;
var _grouping;
var getShape = function (ctx, plyFile, props, shape) { return (0, tslib_1.__awaiter)(_this, void 0, void 0, function () {
var vertex, face, material, newMesh, newColor;
return (0, tslib_1.__generator)(this, function (_a) {
switch (_a.label) {
case 0:
vertex = plyFile.getElement('vertex');
if (!vertex)
throw new Error('missing vertex element');
face = plyFile.getElement('face');
if (!face)
throw new Error('missing face element');
material = plyFile.getElement('material');
newMesh = false;
newColor = false;
if (!_plyFile || _plyFile !== plyFile) {
newMesh = true;
}
if (!_props || !param_definition_1.ParamDefinition.isParamEqual(exports.PlyShapeParams.grouping, _props.grouping, props.grouping)) {
newMesh = true;
}
if (!_props || !param_definition_1.ParamDefinition.isParamEqual(exports.PlyShapeParams.coloring, _props.coloring, props.coloring)) {
newColor = true;
}
if (!newMesh) return [3 /*break*/, 2];
_coloring = getColoring(vertex, material, props);
_grouping = getGrouping(vertex, props);
return [4 /*yield*/, getMesh(ctx, vertex, face, _grouping.ids, shape && shape.geometry)];
case 1:
_mesh = _a.sent();
_shape = createShape(plyFile, _mesh, _coloring, _grouping);
return [3 /*break*/, 3];
case 2:
if (newColor) {
_coloring = getColoring(vertex, material, props);
_shape = createShape(plyFile, _mesh, _coloring, _grouping);
}
_a.label = 3;
case 3:
_plyFile = plyFile;
_props = (0, object_1.deepClone)(props);
return [2 /*return*/, _shape];
}
});
}); };
return getShape;
}
function shapeFromPly(source, params) {
var _this = this;
return mol_task_1.Task.create('Shape Provider', function (ctx) { return (0, tslib_1.__awaiter)(_this, void 0, void 0, function () {
return (0, tslib_1.__generator)(this, function (_a) {
return [2 /*return*/, {
label: 'Mesh',
data: source,
params: createPlyShapeParams(source),
getShape: makeShapeGetter(),
geometryUtils: mesh_1.Mesh.Utils
}];
});
}); });
}
exports.shapeFromPly = shapeFromPly;
//# sourceMappingURL=ply.js.map