diff --git a/src/mol-geo/mesh/mesh-builder.ts b/src/mol-geo/mesh/mesh-builder.ts index b4b3b9c6a952afacafd53c4fbd9f877099b4dfaf..94bff6a0f0446931a08b42fff19671812b7ce7fe 100644 --- a/src/mol-geo/mesh/mesh-builder.ts +++ b/src/mol-geo/mesh/mesh-builder.ts @@ -8,9 +8,9 @@ import { ValueCell } from 'mol-util/value-cell' import { Vec3, Mat4, Mat3 } from 'mol-math/linear-algebra'; import { ChunkedArray } from 'mol-data/util'; -import { Plane, PlaneProps } from '../primitive/plane'; +import { Plane } from '../primitive/plane'; import { Cylinder, CylinderProps } from '../primitive/cylinder'; -import { Sphere, SphereProps } from '../primitive/sphere'; +import { Sphere } from '../primitive/sphere'; import { Mesh } from './mesh'; import { getNormalMatrix } from '../util'; import { addSheet } from './sheet'; @@ -31,9 +31,11 @@ export interface MeshBuilderState { export interface MeshBuilder { add(t: Mat4, _vertices: ArrayLike<number>, _normals: ArrayLike<number>, _indices?: ArrayLike<number>): void + addPrimitive(t: Mat4, primitive: Primitive): void, + addBox(t: Mat4): void addPerforatedBox(t: Mat4): void - addPlane(t: Mat4, props?: PlaneProps): void + addPlane(t: Mat4): void addWedge(t: Mat4): void addDiamondPrism(t: Mat4): void addPentagonalPrism(t: Mat4): void @@ -43,18 +45,21 @@ export interface MeshBuilder { addStar(t: Mat4, props?: StarProps): void addOctahedron(t: Mat4): void addPerforatedOctahedron(t: Mat4): void + addCylinder(start: Vec3, end: Vec3, lengthScale: number, props: CylinderProps): void addDoubleCylinder(start: Vec3, end: Vec3, lengthScale: number, shift: Vec3, props: CylinderProps): void addFixedCountDashedCylinder(start: Vec3, end: Vec3, lengthScale: number, segmentCount: number, props: CylinderProps): void addSphere(center: Vec3, radius: number, detail: number): void + addTube(centers: ArrayLike<number>, normals: ArrayLike<number>, binormals: ArrayLike<number>, linearSegments: number, radialSegments: number, width: number, height: number, waveFactor: number, startCap: boolean, endCap: boolean): void addSheet(centers: ArrayLike<number>, normals: ArrayLike<number>, binormals: ArrayLike<number>, linearSegments: number, width: number, height: number, arrowHeight: number, startCap: boolean, endCap: boolean): void + setGroup(id: number): void getMesh(): Mesh } const cylinderMap = new Map<string, Primitive>() -const sphereMap = new Map<string, Primitive>() +const sphereMap = new Map<number, Primitive>() const up = Vec3.create(0, 1, 0) const tmpV = Vec3.zero() @@ -64,7 +69,6 @@ const tmpCylinderDir = Vec3.zero() const tmpCylinderMatDir = Vec3.zero() const tmpCylinderCenter = Vec3.zero() const tmpCylinderMat = Mat4.zero() -// const tmpCylinderMatTrans = Mat4.zero() const tmpCylinderStart = Vec3.zero() const tmpUp = Vec3.zero() @@ -91,22 +95,19 @@ function getCylinder(props: CylinderProps) { const tmpSphereMat = Mat4.identity() -function setSphereMat(m: Mat4, center: Vec3) { - return Mat4.setTranslation(m, center) +function setSphereMat(m: Mat4, center: Vec3, radius: number) { + return Mat4.scaleUniformly(m, Mat4.fromTranslation(m, center), radius) } -function getSphere(props: SphereProps) { - const key = JSON.stringify(props) - let sphere = sphereMap.get(key) +function getSphere(detail: number) { + let sphere = sphereMap.get(detail) if (sphere === undefined) { - sphere = Sphere(props) - sphereMap.set(key, sphere) + sphere = Sphere(detail) + sphereMap.set(detail, sphere) } return sphere } -// TODO cache primitives based on props - export namespace MeshBuilder { export function create(initialCount = 2048, chunkSize = 1024, mesh?: Mesh): MeshBuilder { const vertices = ChunkedArray.create(Float32Array, 3, chunkSize, mesh ? mesh.vertexBuffer.ref.value : initialCount); @@ -118,97 +119,66 @@ export namespace MeshBuilder { let currentGroup = -1 - function add(t: Mat4, _vertices: ArrayLike<number>, _normals: ArrayLike<number>, _indices: ArrayLike<number>) { - const { elementCount } = vertices + function add(t: Mat4, va: ArrayLike<number>, na: ArrayLike<number>, ia: ArrayLike<number>) { + const offset = vertices.elementCount const n = getNormalMatrix(tmpMat3, t) - for (let i = 0, il = _vertices.length; i < il; i += 3) { + for (let i = 0, il = va.length; i < il; i += 3) { // position - Vec3.fromArray(tmpV, _vertices, i) - Vec3.transformMat4(tmpV, tmpV, t) + Vec3.transformMat4(tmpV, Vec3.fromArray(tmpV, va, i), t) ChunkedArray.add3(vertices, tmpV[0], tmpV[1], tmpV[2]); // normal - Vec3.fromArray(tmpV, _normals, i) - Vec3.transformMat3(tmpV, tmpV, n) + Vec3.transformMat3(tmpV, Vec3.fromArray(tmpV, na, i), n) ChunkedArray.add3(normals, tmpV[0], tmpV[1], tmpV[2]); // group ChunkedArray.add(groups, currentGroup); } - for (let i = 0, il = _indices.length; i < il; i += 3) { - ChunkedArray.add3(indices, _indices[i] + elementCount, _indices[i + 1] + elementCount, _indices[i + 2] + elementCount); + for (let i = 0, il = ia.length; i < il; i += 3) { + ChunkedArray.add3(indices, ia[i] + offset, ia[i + 1] + offset, ia[i + 2] + offset); } } + function addPrimitive(t: Mat4, primitive: Primitive) { + const { vertices, normals, indices } = primitive + add(t, vertices, normals, indices) + } + return { add, - addBox: (t: Mat4) => { - const { vertices, normals, indices } = Box() - add(t, vertices, normals, indices) - }, - addPerforatedBox: (t: Mat4) => { - const { vertices, normals, indices } = PerforatedBox() - add(t, vertices, normals, indices) - }, - addPlane: (t: Mat4, props?: PlaneProps) => { - const { vertices, normals, indices } = Plane(props) - add(t, vertices, normals, indices) - }, - addWedge: (t: Mat4) => { - const { vertices, normals, indices } = Wedge() - add(t, vertices, normals, indices) - }, - addDiamondPrism: (t: Mat4) => { - const { vertices, normals, indices } = DiamondPrism() - add(t, vertices, normals, indices) - }, - addPentagonalPrism: (t: Mat4) => { - const { vertices, normals, indices } = PentagonalPrism() - add(t, vertices, normals, indices) - }, - addHexagonalPrism: (t: Mat4) => { - const { vertices, normals, indices } = HexagonalPrism() - add(t, vertices, normals, indices) - }, - addOctagonalPyramid: (t: Mat4) => { - const { vertices, normals, indices } = OctagonalPyramide() - add(t, vertices, normals, indices) - }, - addPerforatedOctagonalPyramid: (t: Mat4) => { - const { vertices, normals, indices } = PerforatedOctagonalPyramid() - add(t, vertices, normals, indices) - }, - addStar: (t: Mat4, props?: StarProps) => { - const { vertices, normals, indices } = Star(props) - add(t, vertices, normals, indices) - }, - addOctahedron: (t: Mat4) => { - const { vertices, normals, indices } = Octahedron() - add(t, vertices, normals, indices) - }, - addPerforatedOctahedron: (t: Mat4) => { - const { vertices, normals, indices } = PerforatedOctahedron() - add(t, vertices, normals, indices) - }, + addPrimitive, + + addBox: (t: Mat4) => addPrimitive(t, Box()), + addPerforatedBox: (t: Mat4) => addPrimitive(t, PerforatedBox()), + addPlane: (t: Mat4) => addPrimitive(t, Plane()), + addWedge: (t: Mat4) => addPrimitive(t, Wedge()), + addDiamondPrism: (t: Mat4) => addPrimitive(t, DiamondPrism()), + addPentagonalPrism: (t: Mat4) => addPrimitive(t, PentagonalPrism()), + addHexagonalPrism: (t: Mat4) => addPrimitive(t, HexagonalPrism()), + addOctagonalPyramid: (t: Mat4) => addPrimitive(t, OctagonalPyramide()), + addPerforatedOctagonalPyramid: (t: Mat4) => addPrimitive(t, PerforatedOctagonalPyramid()), + addStar: (t: Mat4, props?: StarProps) => addPrimitive(t, Star(props)), + addOctahedron: (t: Mat4) => addPrimitive(t, Octahedron()), + addPerforatedOctahedron: (t: Mat4) => addPrimitive(t, PerforatedOctahedron()), + addCylinder: (start: Vec3, end: Vec3, lengthScale: number, props: CylinderProps) => { const d = Vec3.distance(start, end) * lengthScale props.height = d - const { vertices, normals, indices } = getCylinder(props) Vec3.sub(tmpCylinderDir, end, start) setCylinderMat(tmpCylinderMat, start, tmpCylinderDir, d) - add(tmpCylinderMat, vertices, normals, indices) + addPrimitive(tmpCylinderMat, getCylinder(props)) }, addDoubleCylinder: (start: Vec3, end: Vec3, lengthScale: number, shift: Vec3, props: CylinderProps) => { const d = Vec3.distance(start, end) * lengthScale props.height = d - const { vertices, normals, indices } = getCylinder(props) + const cylinder = getCylinder(props) Vec3.sub(tmpCylinderDir, end, start) // positivly shifted cylinder Vec3.add(tmpCylinderStart, start, shift) setCylinderMat(tmpCylinderMat, tmpCylinderStart, tmpCylinderDir, d) - add(tmpCylinderMat, vertices, normals, indices) + addPrimitive(tmpCylinderMat, cylinder) // negativly shifted cylinder Vec3.sub(tmpCylinderStart, start, shift) setCylinderMat(tmpCylinderMat, tmpCylinderStart, tmpCylinderDir, d) - add(tmpCylinderMat, vertices, normals, indices) + addPrimitive(tmpCylinderMat, cylinder) }, addFixedCountDashedCylinder: (start: Vec3, end: Vec3, lengthScale: number, segmentCount: number, props: CylinderProps) => { const s = Math.floor(segmentCount / 2) @@ -223,7 +193,7 @@ export namespace MeshBuilder { const d = Vec3.distance(start, end) * lengthScale props.height = d * step - const { vertices, normals, indices } = getCylinder(props) + const cylinder = getCylinder(props) Vec3.sub(tmpCylinderDir, end, start) for (let j = 0; j < s; ++j) { @@ -231,14 +201,13 @@ export namespace MeshBuilder { Vec3.setMagnitude(tmpCylinderDir, tmpCylinderDir, d * f) Vec3.add(tmpCylinderStart, start, tmpCylinderDir) setCylinderMat(tmpCylinderMat, tmpCylinderStart, tmpCylinderDir, d * step) - add(tmpCylinderMat, vertices, normals, indices) + addPrimitive(tmpCylinderMat, cylinder) } }, addSphere: (center: Vec3, radius: number, detail: number) => { - const { vertices, normals, indices } = getSphere({ radius, detail }) - setSphereMat(tmpSphereMat, center) - add(tmpSphereMat, vertices, normals, indices) + addPrimitive(setSphereMat(tmpSphereMat, center, radius), getSphere(detail)) }, + addTube: (centers: ArrayLike<number>, normals: ArrayLike<number>, binormals: ArrayLike<number>, linearSegments: number, radialSegments: number, width: number, height: number, waveFactor: number, startCap: boolean, endCap: boolean) => { const addedVertexCount = addTube(centers, normals, binormals, linearSegments, radialSegments, width, height, waveFactor, startCap, endCap, state) for (let i = 0, il = addedVertexCount; i < il; ++i) ChunkedArray.add(groups, currentGroup); @@ -247,6 +216,7 @@ export namespace MeshBuilder { const addedVertexCount = addSheet(controls, normals, binormals, linearSegments, width, height, arrowHeight, startCap, endCap, state) for (let i = 0, il = addedVertexCount; i < il; ++i) ChunkedArray.add(groups, currentGroup); }, + setGroup: (group: number) => { currentGroup = group }, diff --git a/src/mol-geo/primitive/plane.ts b/src/mol-geo/primitive/plane.ts index aeeeb371d933a4f18a333709790d626cd505a19b..2f30c427d4fd4ccf7794b135ae2169aa3793e917 100644 --- a/src/mol-geo/primitive/plane.ts +++ b/src/mol-geo/primitive/plane.ts @@ -6,31 +6,25 @@ import { Primitive } from './primitive'; * @author Alexander Rose <alexander.rose@weirdbyte.de> */ -export const DefaultPlaneProps = { - width: 1, - height: 1 +const plane: Primitive = { + vertices: new Float32Array([ + -0.5, 0.5, 0, + 0.5, 0.5, 0, + -0.5, -0.5, 0, + 0.5, -0.5, 0 + ]), + normals: new Float32Array([ + 0, 0, 1, + 0, 0, 1, + 0, 0, 1, + 0, 0, 1 + ]), + indices: new Uint32Array([ + 0, 2, 1, + 1, 2, 3 + ]) } -export type PlaneProps = Partial<typeof DefaultPlaneProps> -export function Plane(props?: PlaneProps): Primitive { - const { width, height } = { ...DefaultPlaneProps, ...props } - - return { - vertices: new Float32Array([ - -width / 2, height / 2, 0, - width / 2, height / 2, 0, - -width / 2, -height / 2, 0, - width / 2, -height / 2, 0 - ]), - normals: new Float32Array([ - 0, 0, 1, - 0, 0, 1, - 0, 0, 1, - 0, 0, 1 - ]), - indices: new Uint32Array([ - 0, 2, 1, - 1, 2, 3 - ]) - } +export function Plane(): Primitive { + return plane } \ No newline at end of file diff --git a/src/mol-geo/primitive/sphere.ts b/src/mol-geo/primitive/sphere.ts index bcf1460dca677832fa68f057e4ef87b2ca6d87b8..25704b7c1be233d7240a7521795d09db3cde41b2 100644 --- a/src/mol-geo/primitive/sphere.ts +++ b/src/mol-geo/primitive/sphere.ts @@ -15,13 +15,7 @@ export function sphereVertexCount(detail: number) { return 10 * Math.pow(Math.pow(2, detail), 2) + 2 } -export const DefaultSphereProps = { - radius: 1, - detail: 0 -} -export type SphereProps = Partial<typeof DefaultSphereProps> - /** Create sphere by subdividing an icosahedron */ -export function Sphere(props?: SphereProps): Primitive { - return Polyhedron(vertices, indices, { ...DefaultSphereProps, ...props }) +export function Sphere(detail: number): Primitive { + return Polyhedron(vertices, indices, { detail, radius: 1 }) } \ No newline at end of file diff --git a/src/mol-math/linear-algebra/3d/vec3.ts b/src/mol-math/linear-algebra/3d/vec3.ts index 2527ca8724068857a12562845ee7895800901c72..f2f0e1427e87cd980e42d676a5a3d1f62db091a7 100644 --- a/src/mol-math/linear-algebra/3d/vec3.ts +++ b/src/mol-math/linear-algebra/3d/vec3.ts @@ -50,13 +50,13 @@ namespace Vec3 { v[0] = array[offset + 0] v[1] = array[offset + 1] v[2] = array[offset + 2] + return v } export function toArray(v: Vec3, out: Helpers.NumberArray, offset: number) { out[offset + 0] = v[0] out[offset + 1] = v[1] out[offset + 2] = v[2] - return v } export function create(x: number, y: number, z: number): Vec3 { diff --git a/src/mol-view/stage.ts b/src/mol-view/stage.ts index 859dc8b3552fccd7358f0f7c0bd0236bf72c4faa..52e3f619e0ee243b9c0f33434d248982e97cf394 100644 --- a/src/mol-view/stage.ts +++ b/src/mol-view/stage.ts @@ -91,7 +91,7 @@ export class Stage { // this.loadPdbid('3pqr') // inter unit bonds, two polymer chains, ligands, water, carbohydrates linked to protein // this.loadPdbid('4v5a') // ribosome // this.loadPdbid('3j3q') // ... - this.loadPdbid('2np2') // dna + // this.loadPdbid('2np2') // dna // this.loadPdbid('1d66') // dna // this.loadPdbid('9dna') // A form dna // this.loadPdbid('1bna') // B form dna @@ -107,7 +107,7 @@ export class Stage { // this.loadPdbid('1sfi') // contains cyclic peptid // this.loadPdbid('3sn6') // discontinuous chains // this.loadPdbid('2zex') // contains carbohydrate polymer - // this.loadPdbid('3sgj') // contains carbohydrate polymer + this.loadPdbid('3sgj') // contains carbohydrate polymer // this.loadPdbid('3ina') // contains GlcN and IdoA // this.loadPdbid('1umz') // contains Xyl (Xyloglucan) // this.loadPdbid('1mfb') // contains Abe