Alexander Rose 6 лет назад
Родитель
Сommit
84716c3e93

+ 74 - 0
src/mol-geo/primitive/star.ts

@@ -0,0 +1,74 @@
+/**
+ * Copyright (c) 2018 mol* contributors, licensed under MIT, See LICENSE file for more info.
+ *
+ * @author Alexander Rose <alexander.rose@weirdbyte.de>
+ */
+
+import { Vec3 } from 'mol-math/linear-algebra'
+
+export const DefaultStarProps = {
+    pointCount: 5,
+    outerRadius: 1,
+    innerRadius: 0.5,
+    thickness: 0.3
+}
+export type StarProps = Partial<typeof DefaultStarProps>
+
+const op = Vec3.zero()
+const on = Vec3.zero()
+const vn = Vec3.zero()
+const p1 = Vec3.zero()
+const p2 = Vec3.zero()
+const p3 = Vec3.zero()
+
+export function Star(props?: StarProps) {
+    const { outerRadius, innerRadius, thickness, pointCount } = { ...DefaultStarProps, ...props }
+
+    const triangleCount = pointCount * 2 * 2
+    const vertexCount = triangleCount * 3
+
+    const vertices = new Float32Array(vertexCount * 3)
+    const normals = new Float32Array(vertexCount * 3)
+    const indices = new Uint32Array(triangleCount * 3)
+
+    const innerPoints = new Float32Array(pointCount * 2)
+    const outerPoints = new Float32Array(pointCount * 2)
+
+    for (let i = 0; i < pointCount; ++i) {
+        const io = i * 2, ii = i * 2 + 1
+        const co = io / pointCount * Math.PI, ci = ii / pointCount * Math.PI
+        outerPoints[io] = Math.cos(co) * outerRadius
+        outerPoints[ii] = Math.sin(co) * outerRadius
+        innerPoints[io] = Math.cos(ci) * innerRadius
+        innerPoints[ii] = Math.sin(ci) * innerRadius
+    }
+
+    Vec3.set(op, 0, 0, thickness / 2)
+    Vec3.set(on, 0, 0, -thickness / 2)
+
+    function add(a: Vec3, b: Vec3, c: Vec3, offset: number) {
+        Vec3.toArray(a, vertices, offset)
+        Vec3.toArray(b, vertices, offset + 3)
+        Vec3.toArray(c, vertices, offset + 6)
+        Vec3.triangleNormal(vn, a, b, c)
+        for (let j = 0; j < 3; ++j) {
+            Vec3.toArray(vn, normals, offset + 3 * j)
+            indices[offset / 3 + j] = offset / 3 + j
+        }
+    }
+
+    for (let i = 0; i < pointCount; ++i) {
+        const ni = (i + 1) % pointCount
+        Vec3.set(p1, outerPoints[i * 2], outerPoints[i * 2 + 1], 0)
+        Vec3.set(p2, innerPoints[i * 2], innerPoints[i * 2 + 1], 0)
+        Vec3.set(p3, outerPoints[ni * 2], outerPoints[ni * 2 + 1], 0)
+
+        const offset = i * 3 * 3 * 4
+        add(op, p1, p2, offset)
+        add(on, p1, p2, offset + 9)
+        add(op, p2, p3, offset + 18)
+        add(on, p2, p3, offset + 27)
+    }
+
+    return { vertices, normals, indices }
+}

+ 6 - 2
src/mol-geo/representation/structure/visual/carbohydrate-symbol-mesh.ts

@@ -51,7 +51,7 @@ async function createCarbohydrateSymbolMesh(ctx: RuntimeContext, structure: Stru
         const shapeType = getSaccharideShape(c.component.type)
         switch (shapeType) {
             case SaccharideShapes.FilledSphere:
-                builder.addIcosahedron(c.center, radius, 1)
+                builder.addIcosahedron(c.center, radius, 2)
                 break;
             case SaccharideShapes.FilledCube:
                 centerAlign(c.center, c.normal, c.direction)
@@ -65,6 +65,7 @@ async function createCarbohydrateSymbolMesh(ctx: RuntimeContext, structure: Stru
             case SaccharideShapes.FilledCone:
                 Vec3.scaleAndAdd(p1, c.center, c.normal, radius)
                 Vec3.scaleAndSub(p2, c.center, c.normal, radius)
+                // TODO fix cylinder direction flipping code
                 builder.addCylinder(p1, p2, 1, coneParams)
                 break
             case SaccharideShapes.DevidedCone:
@@ -77,9 +78,12 @@ async function createCarbohydrateSymbolMesh(ctx: RuntimeContext, structure: Stru
                 centerAlign(c.center, c.normal, c.direction)
                 builder.addBox(t, { width: side, height: side / 2, depth: side })
                 break
+            case SaccharideShapes.FilledStar:
+                centerAlign(c.center, c.normal, c.direction)
+                builder.addStar(t, { outerRadius: side, innerRadius: side / 2, thickness: side / 2, pointCount: 5 })
+                break
             case SaccharideShapes.FilledDiamond:
             case SaccharideShapes.DividedDiamond:
-            case SaccharideShapes.FilledStar:
             case SaccharideShapes.FlatDiamond:
             case SaccharideShapes.Pentagon:
                 centerAlign(c.center, c.normal, c.direction)

+ 6 - 0
src/mol-geo/shape/mesh-builder.ts

@@ -17,6 +17,7 @@ import { Mesh } from './mesh';
 import { getNormalMatrix } from '../util';
 import { addSheet } from '../primitive/sheet';
 import { addTube } from '../primitive/tube';
+import { StarProps, Star } from '../primitive/star';
 
 interface Primitive {
     vertices: Float32Array
@@ -35,6 +36,7 @@ export interface MeshBuilder {
     addBox(t: Mat4, props?: BoxProps): void
     addPlane(t: Mat4, props?: PlaneProps): void
     addWedge(t: Mat4, props?: WedgeProps): void
+    addStar(t: Mat4, props?: StarProps): 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
@@ -143,6 +145,10 @@ export namespace MeshBuilder {
                 const { vertices, normals, indices } = Wedge(props)
                 add(t, vertices, normals, indices)
             },
+            addStar: (t: Mat4, props?: StarProps) => {
+                const { vertices, normals, indices } = Star(props)
+                add(t, vertices, normals, indices)
+            },
             addCylinder: (start: Vec3, end: Vec3, lengthScale: number, props: CylinderProps) => {
                 const d = Vec3.distance(start, end) * lengthScale
                 props.height = d

+ 10 - 1
src/mol-math/linear-algebra/3d/vec3.ts

@@ -454,13 +454,22 @@ namespace Vec3 {
     }
 
     const orthogonalizeTmp = zero();
-    /** Get a vector that is similar to b but orthogonal to a */
+    /** Get a vector that is similar to `b` but orthogonal to `a` */
     export function orthogonalize(out: Vec3, a: Vec3, b: Vec3) {
         normalize(orthogonalizeTmp, cross(orthogonalizeTmp, a, b));
         normalize(out, cross(out, orthogonalizeTmp, a));
         return out;
     }
 
+    const triangleNormalTmpAB = zero();
+    const triangleNormalTmpAC = zero();
+    /** Calculate normal for the triangle defined by `a`, `b` and `c` */
+    export function triangleNormal(out: Vec3, a: Vec3, b: Vec3, c: Vec3) {
+        sub(triangleNormalTmpAB, b, a);
+        sub(triangleNormalTmpAC, c, a);
+        return normalize(out, cross(out, triangleNormalTmpAB, triangleNormalTmpAC));
+    }
+
     export function toString(a: Vec3) {
         return `[${a[0]} ${a[1]} ${a[2]}]`;
     }