Browse Source

simplified primitive handling in mesh-builder

Alexander Rose 6 years ago
parent
commit
6828e78fdf

+ 51 - 81
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
             },

+ 19 - 25
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
 }

+ 2 - 8
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 })
 }

+ 1 - 1
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 {

+ 2 - 2
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