Browse Source

adds visuals

JonStargaryen 4 years ago
parent
commit
6c78adb353

+ 102 - 15
src/extensions/membrane-orientation/representation.ts

@@ -6,7 +6,7 @@
  */
 
 import { ParamDefinition as PD } from '../../mol-util/param-definition';
-import { Vec3 } from '../../mol-math/linear-algebra';
+import { Vec3, Mat4 } from '../../mol-math/linear-algebra';
 import { Representation, RepresentationContext, RepresentationParamsGetter } from '../../mol-repr/representation';
 import { Structure } from '../../mol-model/structure';
 import { Spheres } from '../../mol-geo/geometry/spheres/spheres';
@@ -19,13 +19,55 @@ import { ShapeRepresentation } from '../../mol-repr/shape/representation';
 import { Shape } from '../../mol-model/shape';
 import { ColorNames } from '../../mol-util/color/names';
 import { RuntimeContext } from '../../mol-task';
+import { Lines } from '../../mol-geo/geometry/lines/lines';
+import { Mesh } from '../../mol-geo/geometry/mesh/mesh';
+import { LinesBuilder } from '../../mol-geo/geometry/lines/lines-builder';
+import { Circle } from '../../mol-geo/primitive/circle';
+import { transformPrimitive } from '../../mol-geo/primitive/primitive';
+import { MeshBuilder } from '../../mol-geo/geometry/mesh/mesh-builder';
 
-const MembraneOrientationParams = {
+const SharedParams = {
+    color: PD.Color(ColorNames.lightgrey)
+};
+
+const BilayerSpheresParams = {
+    ...SharedParams,
     ...Spheres.Params,
-    color: PD.Color(ColorNames.lightgrey),
     size: PD.Numeric(1, { min: 0.1, max: 10, step: 0.1 }, { description: 'Size of spheres that represent membrane planes' }),
     density: PD.Numeric(1, { min: 0.25, max: 10, step: 0.25 }, { description: 'Distance between spheres'})
 };
+export type BilayerSpheresParams = typeof BilayerSpheresParams
+export type BilayerSpheresProps = PD.Values<BilayerSpheresParams>
+
+const BilayerPlanesParams = {
+    ...SharedParams,
+    ...Mesh.Params
+};
+export type BilayerPlanesParams = typeof BilayerPlanesParams
+export type BilayerPlanesProps = PD.Values<BilayerPlanesParams>
+
+const BilayerRimsParams = {
+    ...SharedParams,
+    ...Lines.Params,
+    lineSizeAttenuation: PD.Boolean(true),
+    linesSize: PD.Numeric(0.04, { min: 0.01, max: 5, step: 0.01 }),
+    dashLength: PD.Numeric(0.04, { min: 0.01, max: 0.2, step: 0.01 })
+};
+export type BilayerRimsParams = typeof BilayerRimsParams
+export type BilayerRimsProps = PD.Values<BilayerRimsParams>
+
+const MembraneOrientationVisuals = {
+    'bilayer-spheres': (ctx: RepresentationContext, getParams: RepresentationParamsGetter<MembraneOrientation, BilayerSpheresParams>) => ShapeRepresentation(getBilayerSpheres, Spheres.Utils, { modifyState: s => ({ ...s, pickable: false }) }),
+    'bilayer-planes': (ctx: RepresentationContext, getParams: RepresentationParamsGetter<MembraneOrientation, BilayerPlanesParams>) => ShapeRepresentation(getBilayerPlanes, Mesh.Utils, { modifyState: s => ({ ...s, pickable: false }) }),
+    'bilayer-rims': (ctx: RepresentationContext, getParams: RepresentationParamsGetter<MembraneOrientation, BilayerRimsParams>) => ShapeRepresentation(getBilayerRims, Lines.Utils, { modifyState: s => ({ ...s, pickable: false }) })
+};
+
+export const MembraneOrientationParams = {
+    ...BilayerSpheresParams,
+    ...BilayerPlanesParams,
+    ...BilayerRimsParams,
+    visuals: PD.MultiSelect(['bilayer-spheres', 'bilayer-planes', 'bilayer-rims'], PD.objectToOptions(MembraneOrientationVisuals)),
+};
 export type MembraneOrientationParams = typeof MembraneOrientationParams
 export type MembraneOrientationProps = PD.Values<MembraneOrientationParams>
 
@@ -38,11 +80,6 @@ export function MembraneOrientationRepresentation(ctx: RepresentationContext, ge
     return Representation.createMulti('Membrane Orientation', ctx, getParams, StructureRepresentationStateBuilder, MembraneOrientationVisuals as unknown as Representation.Def<Structure, MembraneOrientationParams>);
 }
 
-const MembraneOrientationVisuals = {
-    'membrane-orientation': (ctx: RepresentationContext, getParams: RepresentationParamsGetter<MembraneOrientation, MembraneOrientationParams>) => ShapeRepresentation(getMembraneSpheres, Spheres.Utils),
-};
-
-
 export const MembraneOrientationRepresentationProvider = StructureRepresentationProvider({
     name: 'membrane-orientation',
     label: 'Membrane Orientation',
@@ -55,24 +92,74 @@ export const MembraneOrientationRepresentationProvider = StructureRepresentation
     isApplicable: (structure: Structure) => structure.elementCount > 0
 });
 
-function getMembraneSpheres(ctx: RuntimeContext, data: Structure, props: MembraneOrientationProps) {
+function getBilayerRims(ctx: RuntimeContext, data: Structure, props: BilayerRimsProps): Shape<Lines> {
+    const { p1, p2, centroid, normal, radius } = MembraneOrientationProvider.get(data).value!;
+    const builder = LinesBuilder.create(128, 64);
+    getLayerCircle(builder, p1, centroid, normal, radius);
+    getLayerCircle(builder, p2, centroid, normal, radius);
+    return Shape.create(name, data, builder.getLines(), () => props.color, () => /*props.linesSize*/1, () => '');
+}
+
+function getLayerCircle(builder: LinesBuilder, p: Vec3, centroid: Vec3, normal: Vec3, radius: number) {
+    const circle = getCircle(p, centroid, normal, radius);
+    const { indices, vertices } = circle;
+    for (let j = 0, jl = indices.length; j < jl; j += 3) {
+        if (j % 2 === 1) continue; // draw every other segment to get dashes
+        const start = indices[j] * 3;
+        const end = indices[j + 1] * 3;
+        const startX = vertices[start];
+        const startY = vertices[start + 1];
+        const startZ = vertices[start + 2];
+        const endX = vertices[end];
+        const endY = vertices[end + 1];
+        const endZ = vertices[end + 2];
+        builder.add(startX, startY, startZ, endX, endY, endZ, 0);
+    }
+}
+
+const tmpMat = Mat4();
+function getCircle(p: Vec3, centroid: Vec3, normal: Vec3, radius: number) {
+    Mat4.targetTo(tmpMat, p, centroid, normal);
+    Mat4.setTranslation(tmpMat, p);
+    Mat4.mul(tmpMat, tmpMat, Mat4.rotX90);
+
+    const circle = Circle({ radius });
+    return transformPrimitive(circle, tmpMat);
+}
+
+function getBilayerPlanes(ctx: RuntimeContext, data: Structure, props: BilayerPlanesProps): Shape<Mesh> {
+    const { p1, p2, centroid, normal, radius } = MembraneOrientationProvider.get(data).value!;
+    const state = MeshBuilder.createState(128, 64);
+    getLayerPlane(state, p1, centroid, normal, radius);
+    getLayerPlane(state, p2, centroid, normal, radius);
+    return Shape.create(name, data, MeshBuilder.getMesh(state), () => props.color, () => /*props.size*/1, () => '');
+}
+
+function getLayerPlane(state: MeshBuilder.State, p: Vec3, centroid: Vec3, normal: Vec3, radius: number) {
+    const circle = getCircle(p, centroid, normal, radius);
+    state.currentGroup = 0;
+    MeshBuilder.addPrimitive(state, Mat4.id, circle);
+    MeshBuilder.addPrimitiveFlipped(state, Mat4.id, circle);
+}
+
+function getBilayerSpheres(ctx: RuntimeContext, data: Structure, props: BilayerSpheresProps): Shape<Spheres> {
     const { density } = props;
-    const { radius, p1, p2, normal } = MembraneOrientationProvider.get(data).value!;;
+    const { radius, p1, p2, normal } = MembraneOrientationProvider.get(data).value!;
 
     const spheresBuilder = SpheresBuilder.create();
-    createMembraneLayer(spheresBuilder, p1, normal, density, radius);
-    createMembraneLayer(spheresBuilder, p2, normal, density, radius);
-    return Shape.create(name, data, spheresBuilder.getSpheres(), () => props.color, () => props.size, () => 'Membrane Boundaries');
+    getLayerSpheres(spheresBuilder, p1, normal, density, radius * radius);
+    getLayerSpheres(spheresBuilder, p2, normal, density, radius * radius);
+    return Shape.create(name, data, spheresBuilder.getSpheres(), () => props.color, () => props.size, () => '');
 }
 
-function createMembraneLayer(spheresBuilder: SpheresBuilder, point: Vec3, normalVector: Vec3, density: number, radius: number) {
+function getLayerSpheres(spheresBuilder: SpheresBuilder, point: Vec3, normalVector: Vec3, density: number, sqRadius: number) {
     Vec3.normalize(normalVector, normalVector);
     const d = -Vec3.dot(normalVector, point);
     const rep = Vec3();
     for (let i = -1000, il = 1000; i < il; i += density) {
         for (let j = -1000, jl = 1000; j < jl; j += density) {
             Vec3.set(rep, i, j, normalVector[2] === 0 ? 0 : -(d + i * normalVector[0] + j * normalVector[1]) / normalVector[2]);
-            if (Vec3.squaredDistance(rep, point) < radius) {
+            if (Vec3.squaredDistance(rep, point) < sqRadius) {
                 spheresBuilder.add(rep[0], rep[1], rep[2], 0);
             }
         }

+ 1 - 1
src/mol-model-props/computed/membrane-orientation/ANVIL.ts

@@ -123,7 +123,7 @@ export async function calculate(runtime: RuntimeContext, structure: Structure, p
 
     const membrane = initialMembrane.qmax! > alternativeMembrane.qmax! ? initialMembrane : alternativeMembrane;
 
-    return MembraneOrientation(membrane.planePoint1, membrane.planePoint2, membrane.normalVector!, ctx.extent * ctx.extent);
+    return MembraneOrientation(membrane.planePoint1, membrane.planePoint2, membrane.normalVector!, ctx.extent, ctx.centroid);
 }
 
 interface MembraneCandidate {

+ 4 - 3
src/mol-model/structure/model/properties/membrane-orientation.ts

@@ -14,11 +14,12 @@ interface MembraneOrientation {
     // normal vector of membrane layer
     readonly normal: Vec3,
     // the radius of the membrane layer
-    readonly radius: number
+    readonly radius: number,
+    readonly centroid: Vec3
 }
 
-function MembraneOrientation(p1: Vec3, p2: Vec3, normal: Vec3, radius: number): MembraneOrientation {
-    return { p1, p2, normal, radius };
+function MembraneOrientation(p1: Vec3, p2: Vec3, normal: Vec3, radius: number, centroid: Vec3): MembraneOrientation {
+    return { p1, p2, normal, radius, centroid };
 }
 
 export { MembraneOrientation };