Browse Source

perf improvement for intra unit bond visuals

- reorder some if statement to have common case first
- avoid no-op and fixed functions
- const enum
Alexander Rose 4 years ago
parent
commit
909e4b3a9f

+ 4 - 0
src/mol-model/structure/model/types.ts

@@ -643,6 +643,10 @@ export namespace BondType {
         return (flags & BondType.Flag.Covalent) !== 0;
     }
 
+    export function isAll(flags: BondType.Flag) {
+        return flags === Math.pow(2, 6) - 1;
+    }
+
     export const Names = {
         'covalent': Flag.Covalent,
         'metal-coordination': Flag.MetallicCoordination,

+ 18 - 8
src/mol-repr/structure/visual/bond-intra-unit-cylinder.ts

@@ -11,7 +11,7 @@ import { Unit, Structure, StructureElement } from '../../../mol-model/structure'
 import { Theme } from '../../../mol-theme/theme';
 import { Mesh } from '../../../mol-geo/geometry/mesh/mesh';
 import { Vec3 } from '../../../mol-math/linear-algebra';
-import { BitFlags, arrayEqual } from '../../../mol-util';
+import { arrayEqual } from '../../../mol-util';
 import { createLinkCylinderMesh, LinkStyle } from './util/link';
 import { UnitsMeshParams, UnitsVisual, UnitsMeshVisual, StructureGroup } from '../units-visual';
 import { VisualUpdateState } from '../../util';
@@ -21,6 +21,9 @@ import { ignoreBondType, BondCylinderParams, BondIterator, eachIntraBond, getInt
 import { Sphere3D } from '../../../mol-math/geometry';
 import { IntAdjacencyGraph } from '../../../mol-math/graph';
 
+// avoiding namespace lookup improved performance in Chrome (Aug 2020)
+const isBondType = BondType.is;
+
 function createIntraUnitBondCylinderMesh(ctx: VisualContext, unit: Unit, structure: Structure, theme: Theme, props: PD.Values<IntraUnitBondCylinderParams>, mesh?: Mesh) {
     if (!Unit.isAtomic(unit)) return Mesh.createEmpty(mesh);
 
@@ -35,9 +38,16 @@ function createIntraUnitBondCylinderMesh(ctx: VisualContext, unit: Unit, structu
     const include = BondType.fromNames(includeTypes);
     const exclude = BondType.fromNames(excludeTypes);
 
-    const ignoreHydrogen = ignoreHydrogens ? (edgeIndex: number) => {
-        return isHydrogen(unit, elements[a[edgeIndex]]) || isHydrogen(unit, elements[b[edgeIndex]]);
-    } : () => false;
+    const allBondTypes = BondType.isAll(include) && BondType.Flag.None === exclude;
+
+    let ignore: undefined | ((edgeIndex: number) => boolean) = undefined;
+    if (!allBondTypes && ignoreHydrogens) {
+        ignore = (edgeIndex: number) => isHydrogen(unit, elements[a[edgeIndex]]) || isHydrogen(unit, elements[b[edgeIndex]]) || ignoreBondType(include, exclude, _flags[edgeIndex]);
+    } else if (!allBondTypes) {
+        ignore = (edgeIndex: number) => ignoreBondType(include, exclude, _flags[edgeIndex]);
+    } else if (ignoreHydrogens) {
+        ignore = (edgeIndex: number) => isHydrogen(unit, elements[a[edgeIndex]]) || isHydrogen(unit, elements[b[edgeIndex]]);
+    }
 
     if (!edgeCount) return Mesh.createEmpty(mesh);
 
@@ -51,7 +61,7 @@ function createIntraUnitBondCylinderMesh(ctx: VisualContext, unit: Unit, structu
 
             if (aI > bI) [aI, bI] = [bI, aI];
             if (offset[aI + 1] - offset[aI] === 1) [aI, bI] = [bI, aI];
-            // TODO prefer reference atoms in rings
+            // TODO prefer reference atoms within rings
 
             for (let i = offset[aI], il = offset[aI + 1]; i < il; ++i) {
                 const _bI = b[i];
@@ -69,8 +79,8 @@ function createIntraUnitBondCylinderMesh(ctx: VisualContext, unit: Unit, structu
         },
         style: (edgeIndex: number) => {
             const o = _order[edgeIndex];
-            const f = BitFlags.create(_flags[edgeIndex]);
-            if (BondType.is(f, BondType.Flag.MetallicCoordination) || BondType.is(f, BondType.Flag.HydrogenBond)) {
+            const f = _flags[edgeIndex];
+            if (isBondType(f, BondType.Flag.MetallicCoordination) || isBondType(f, BondType.Flag.HydrogenBond)) {
                 // show metall coordinations and hydrogen bonds with dashed cylinders
                 return LinkStyle.Dashed;
             } else if (o === 2) {
@@ -88,7 +98,7 @@ function createIntraUnitBondCylinderMesh(ctx: VisualContext, unit: Unit, structu
             const sizeB = theme.size.size(location);
             return Math.min(sizeA, sizeB) * sizeFactor * sizeAspectRatio;
         },
-        ignore: (edgeIndex: number) => ignoreHydrogen(edgeIndex) || ignoreBondType(include, exclude, _flags[edgeIndex])
+        ignore
     };
 
     const m = createLinkCylinderMesh(ctx, builderProps, props, mesh);

+ 18 - 8
src/mol-repr/structure/visual/bond-intra-unit-line.ts

@@ -9,7 +9,7 @@ import { VisualContext } from '../../visual';
 import { Unit, Structure, StructureElement } from '../../../mol-model/structure';
 import { Theme } from '../../../mol-theme/theme';
 import { Vec3 } from '../../../mol-math/linear-algebra';
-import { BitFlags, arrayEqual } from '../../../mol-util';
+import { arrayEqual } from '../../../mol-util';
 import { LinkStyle, createLinkLines } from './util/link';
 import { UnitsVisual, UnitsLinesParams, UnitsLinesVisual, StructureGroup } from '../units-visual';
 import { VisualUpdateState } from '../../util';
@@ -20,6 +20,9 @@ import { Sphere3D } from '../../../mol-math/geometry';
 import { Lines } from '../../../mol-geo/geometry/lines/lines';
 import { IntAdjacencyGraph } from '../../../mol-math/graph';
 
+// avoiding namespace lookup improved performance in Chrome (Aug 2020)
+const isBondType = BondType.is;
+
 function createIntraUnitBondLines(ctx: VisualContext, unit: Unit, structure: Structure, theme: Theme, props: PD.Values<IntraUnitBondLineParams>, lines?: Lines) {
     if (!Unit.isAtomic(unit)) return Lines.createEmpty(lines);
 
@@ -34,9 +37,16 @@ function createIntraUnitBondLines(ctx: VisualContext, unit: Unit, structure: Str
     const include = BondType.fromNames(includeTypes);
     const exclude = BondType.fromNames(excludeTypes);
 
-    const ignoreHydrogen = ignoreHydrogens ? (edgeIndex: number) => {
-        return isHydrogen(unit, elements[a[edgeIndex]]) || isHydrogen(unit, elements[b[edgeIndex]]);
-    } : () => false;
+    const allBondTypes = BondType.isAll(include) && BondType.Flag.None === exclude;
+
+    let ignore: undefined | ((edgeIndex: number) => boolean) = undefined;
+    if (!allBondTypes && ignoreHydrogens) {
+        ignore = (edgeIndex: number) => isHydrogen(unit, elements[a[edgeIndex]]) || isHydrogen(unit, elements[b[edgeIndex]]) || ignoreBondType(include, exclude, _flags[edgeIndex]);
+    } else if (!allBondTypes) {
+        ignore = (edgeIndex: number) => ignoreBondType(include, exclude, _flags[edgeIndex]);
+    } else if (ignoreHydrogens) {
+        ignore = (edgeIndex: number) => isHydrogen(unit, elements[a[edgeIndex]]) || isHydrogen(unit, elements[b[edgeIndex]]);
+    }
 
     if (!edgeCount) return Lines.createEmpty(lines);
 
@@ -50,7 +60,7 @@ function createIntraUnitBondLines(ctx: VisualContext, unit: Unit, structure: Str
 
             if (aI > bI) [aI, bI] = [bI, aI];
             if (offset[aI + 1] - offset[aI] === 1) [aI, bI] = [bI, aI];
-            // TODO prefer reference atoms in rings
+            // TODO prefer reference atoms within rings
 
             for (let i = offset[aI], il = offset[aI + 1]; i < il; ++i) {
                 const _bI = b[i];
@@ -68,8 +78,8 @@ function createIntraUnitBondLines(ctx: VisualContext, unit: Unit, structure: Str
         },
         style: (edgeIndex: number) => {
             const o = _order[edgeIndex];
-            const f = BitFlags.create(_flags[edgeIndex]);
-            if (BondType.is(f, BondType.Flag.MetallicCoordination) || BondType.is(f, BondType.Flag.HydrogenBond)) {
+            const f = _flags[edgeIndex];
+            if (isBondType(f, BondType.Flag.MetallicCoordination) || isBondType(f, BondType.Flag.HydrogenBond)) {
                 // show metall coordinations and hydrogen bonds with dashed cylinders
                 return LinkStyle.Dashed;
             } else if (o === 2) {
@@ -87,7 +97,7 @@ function createIntraUnitBondLines(ctx: VisualContext, unit: Unit, structure: Str
             const sizeB = theme.size.size(location);
             return Math.min(sizeA, sizeB) * sizeFactor;
         },
-        ignore: (edgeIndex: number) => ignoreHydrogen(edgeIndex) || ignoreBondType(include, exclude, _flags[edgeIndex])
+        ignore
     };
 
     const l = createLinkLines(ctx, builderProps, props, lines);

+ 11 - 12
src/mol-repr/structure/visual/util/link.ts

@@ -71,7 +71,7 @@ export interface LinkBuilderProps {
     ignore?: (edgeIndex: number) => boolean
 }
 
-export enum LinkStyle {
+export const enum LinkStyle {
     Solid = 0,
     Dashed = 1,
     Double = 2,
@@ -120,7 +120,12 @@ export function createLinkCylinderMesh(ctx: VisualContext, linkBuilder: LinkBuil
         const linkStyle = style ? style(edgeIndex) : LinkStyle.Solid;
         builderState.currentGroup = edgeIndex;
 
-        if (linkStyle === LinkStyle.Dashed) {
+        if (linkStyle === LinkStyle.Solid) {
+            cylinderProps.radiusTop = cylinderProps.radiusBottom = linkRadius;
+            cylinderProps.topCap = cylinderProps.bottomCap = linkCap;
+
+            addCylinder(builderState, va, vb, 0.5, cylinderProps);
+        } else if (linkStyle === LinkStyle.Dashed) {
             cylinderProps.radiusTop = cylinderProps.radiusBottom = linkRadius / 3;
             cylinderProps.topCap = cylinderProps.bottomCap = true;
 
@@ -152,11 +157,6 @@ export function createLinkCylinderMesh(ctx: VisualContext, linkBuilder: LinkBuil
                 cylinderProps.bottomCap = false;
             }
 
-            addCylinder(builderState, va, vb, 0.5, cylinderProps);
-        } else {
-            cylinderProps.radiusTop = cylinderProps.radiusBottom = linkRadius;
-            cylinderProps.topCap = cylinderProps.bottomCap = linkCap;
-
             addCylinder(builderState, va, vb, 0.5, cylinderProps);
         }
     }
@@ -188,10 +188,11 @@ export function createLinkLines(ctx: VisualContext, linkBuilder: LinkBuilderProp
         position(va, vb, edgeIndex);
         v3scale(vb, v3add(vb, va, vb), 0.5);
 
-        // TODO use line width?
         const linkStyle = style ? style(edgeIndex) : LinkStyle.Solid;
 
-        if (linkStyle === LinkStyle.Dashed) {
+        if (linkStyle === LinkStyle.Solid) {
+            builder.add(va[0], va[1], va[2], vb[0], vb[1], vb[2], edgeIndex);
+        } else if (linkStyle === LinkStyle.Dashed) {
             builder.addFixedCountDashes(va, vb, 7, edgeIndex);
         } else if (linkStyle === LinkStyle.Double || linkStyle === LinkStyle.Triple) {
             const order = LinkStyle.Double ? 2 : 3;
@@ -209,9 +210,7 @@ export function createLinkLines(ctx: VisualContext, linkBuilder: LinkBuilderProp
             v3add(va, va, tmpV12);
             v3sub(vb, vb, tmpV12);
 
-            // TODO what to do here?
-            builder.add(va[0], va[1], va[2], vb[0], vb[1], vb[2], edgeIndex);
-        } else {
+            // TODO what to do here? Line as disk doesn't work well.
             builder.add(va[0], va[1], va[2], vb[0], vb[1], vb[2], edgeIndex);
         }
     }