UNPKG

molstar

Version:

A comprehensive macromolecular library.

175 lines (174 loc) 8.65 kB
"use strict"; /** * Copyright (c) 2018-2021 mol* contributors, licensed under MIT, See LICENSE file for more info. * * @author Alexander Rose <alexander.rose@weirdbyte.de> * @author David Sehnal <david.sehnal@gmail.com> */ Object.defineProperty(exports, "__esModule", { value: true }); exports.addTube = void 0; var linear_algebra_1 = require("../../../../mol-math/linear-algebra"); var util_1 = require("../../../../mol-data/util"); var normalVector = (0, linear_algebra_1.Vec3)(); var surfacePoint = (0, linear_algebra_1.Vec3)(); var controlPoint = (0, linear_algebra_1.Vec3)(); var u = (0, linear_algebra_1.Vec3)(); var v = (0, linear_algebra_1.Vec3)(); function add2AndScale2(out, a, b, sa, sb) { out[0] = (a[0] * sa) + (b[0] * sb); out[1] = (a[1] * sa) + (b[1] * sb); out[2] = (a[2] * sa) + (b[2] * sb); } function add3AndScale2(out, a, b, c, sa, sb) { out[0] = (a[0] * sa) + (b[0] * sb) + c[0]; out[1] = (a[1] * sa) + (b[1] * sb) + c[1]; out[2] = (a[2] * sa) + (b[2] * sb) + c[2]; } // avoiding namespace lookup improved performance in Chrome (Aug 2020) var v3fromArray = linear_algebra_1.Vec3.fromArray; var v3normalize = linear_algebra_1.Vec3.normalize; var v3scaleAndAdd = linear_algebra_1.Vec3.scaleAndAdd; var v3cross = linear_algebra_1.Vec3.cross; var v3dot = linear_algebra_1.Vec3.dot; var v3unitX = linear_algebra_1.Vec3.unitX; var caAdd3 = util_1.ChunkedArray.add3; var CosSinCache = new Map(); function getCosSin(radialSegments, shift) { var offset = shift ? 1 : 0; var hash = (0, util_1.cantorPairing)(radialSegments, offset); if (!CosSinCache.has(hash)) { var cos = []; var sin = []; for (var j = 0; j < radialSegments; ++j) { var t = (j * 2 + offset) / radialSegments * Math.PI; cos[j] = Math.cos(t); sin[j] = Math.sin(t); } CosSinCache.set(hash, { cos: cos, sin: sin }); } return CosSinCache.get(hash); } function addTube(state, controlPoints, normalVectors, binormalVectors, linearSegments, radialSegments, widthValues, heightValues, startCap, endCap, crossSection) { var currentGroup = state.currentGroup, vertices = state.vertices, normals = state.normals, indices = state.indices, groups = state.groups; var vertexCount = vertices.elementCount; var _a = getCosSin(radialSegments, crossSection === 'rounded'), cos = _a.cos, sin = _a.sin; var q1 = Math.round(radialSegments / 4); var q3 = q1 * 3; for (var i = 0; i <= linearSegments; ++i) { var i3 = i * 3; v3fromArray(u, normalVectors, i3); v3fromArray(v, binormalVectors, i3); v3fromArray(controlPoint, controlPoints, i3); var width = widthValues[i]; var height = heightValues[i]; var rounded = crossSection === 'rounded' && height > width; for (var j = 0; j < radialSegments; ++j) { if (rounded) { add3AndScale2(surfacePoint, u, v, controlPoint, width * cos[j], width * sin[j]); var h = v3dot(v, v3unitX) < 0 ? (j < q1 || j >= q3) ? height - width : -height + width : (j >= q1 && j < q3) ? -height + width : height - width; v3scaleAndAdd(surfacePoint, surfacePoint, u, h); if (j === q1 || j === q1 - 1) { add2AndScale2(normalVector, u, v, 0, 1); } else if (j === q3 || j === q3 - 1) { add2AndScale2(normalVector, u, v, 0, -1); } else { add2AndScale2(normalVector, u, v, cos[j], sin[j]); } } else { add3AndScale2(surfacePoint, u, v, controlPoint, height * cos[j], width * sin[j]); add2AndScale2(normalVector, u, v, width * cos[j], height * sin[j]); } v3normalize(normalVector, normalVector); caAdd3(vertices, surfacePoint[0], surfacePoint[1], surfacePoint[2]); caAdd3(normals, normalVector[0], normalVector[1], normalVector[2]); } } var radialSegmentsHalf = Math.round(radialSegments / 2); for (var i = 0; i < linearSegments; ++i) { // the triangles are arranged such that opposing triangles of the sheet align // which prevents triangle intersection within tight curves for (var j = 0; j < radialSegmentsHalf; ++j) { caAdd3(indices, vertexCount + i * radialSegments + (j + 1) % radialSegments, // a vertexCount + (i + 1) * radialSegments + (j + 1) % radialSegments, // c vertexCount + i * radialSegments + j // b ); caAdd3(indices, vertexCount + (i + 1) * radialSegments + (j + 1) % radialSegments, // c vertexCount + (i + 1) * radialSegments + j, // d vertexCount + i * radialSegments + j // b ); } for (var j = radialSegmentsHalf; j < radialSegments; ++j) { caAdd3(indices, vertexCount + i * radialSegments + (j + 1) % radialSegments, // a vertexCount + (i + 1) * radialSegments + j, // d vertexCount + i * radialSegments + j // b ); caAdd3(indices, vertexCount + (i + 1) * radialSegments + (j + 1) % radialSegments, // c vertexCount + (i + 1) * radialSegments + j, // d vertexCount + i * radialSegments + (j + 1) % radialSegments); } } if (startCap) { var offset = 0; var centerVertex = vertices.elementCount; v3fromArray(u, normalVectors, offset); v3fromArray(v, binormalVectors, offset); v3fromArray(controlPoint, controlPoints, offset); v3cross(normalVector, v, u); caAdd3(vertices, controlPoint[0], controlPoint[1], controlPoint[2]); caAdd3(normals, normalVector[0], normalVector[1], normalVector[2]); var width = widthValues[0]; var height = heightValues[0]; var rounded = crossSection === 'rounded' && height > width; if (rounded) height -= width; vertexCount = vertices.elementCount; for (var i = 0; i < radialSegments; ++i) { if (rounded) { add3AndScale2(surfacePoint, u, v, controlPoint, width * cos[i], width * sin[i]); v3scaleAndAdd(surfacePoint, surfacePoint, u, (i < q1 || i >= q3) ? height : -height); } else { add3AndScale2(surfacePoint, u, v, controlPoint, height * cos[i], width * sin[i]); } caAdd3(vertices, surfacePoint[0], surfacePoint[1], surfacePoint[2]); caAdd3(normals, normalVector[0], normalVector[1], normalVector[2]); caAdd3(indices, vertexCount + (i + 1) % radialSegments, vertexCount + i, centerVertex); } } if (endCap) { var offset = linearSegments * 3; var centerVertex = vertices.elementCount; v3fromArray(u, normalVectors, offset); v3fromArray(v, binormalVectors, offset); v3fromArray(controlPoint, controlPoints, offset); v3cross(normalVector, u, v); caAdd3(vertices, controlPoint[0], controlPoint[1], controlPoint[2]); caAdd3(normals, normalVector[0], normalVector[1], normalVector[2]); var width = widthValues[linearSegments]; var height = heightValues[linearSegments]; var rounded = crossSection === 'rounded' && height > width; if (rounded) height -= width; vertexCount = vertices.elementCount; for (var i = 0; i < radialSegments; ++i) { if (rounded) { add3AndScale2(surfacePoint, u, v, controlPoint, width * cos[i], width * sin[i]); v3scaleAndAdd(surfacePoint, surfacePoint, u, (i < q1 || i >= q3) ? height : -height); } else { add3AndScale2(surfacePoint, u, v, controlPoint, height * cos[i], width * sin[i]); } caAdd3(vertices, surfacePoint[0], surfacePoint[1], surfacePoint[2]); caAdd3(normals, normalVector[0], normalVector[1], normalVector[2]); caAdd3(indices, vertexCount + i, vertexCount + (i + 1) % radialSegments, centerVertex); } } var addedVertexCount = (linearSegments + 1) * radialSegments + (startCap ? radialSegments + 1 : 0) + (endCap ? radialSegments + 1 : 0); util_1.ChunkedArray.addRepeat(groups, addedVertexCount, currentGroup); } exports.addTube = addTube;