ソースを参照

add elements crosses visual

Alexander Rose 3 年 前
コミット
d96eb404e1

+ 1 - 1
CHANGELOG.md

@@ -12,7 +12,7 @@ Note that since we don't clearly distinguish between a public and private interf
 - Add ``preferAtoms`` option to SelectLoci/HighlightLoci behaviors
 - Make the implicit atoms of bond visuals pickable
     - Add ``preferAtomPixelPadding`` to Canvas3dInteractionHelper
-- Add points visual to Line representation
+- Add points & crosses visuals to Line representation
 - Add ``pickPadding`` config option (look around in case target pixel is empty)
 
 ## [v2.3.3] - 2021-10-01

+ 5 - 2
src/mol-repr/structure/representation/line.ts

@@ -15,21 +15,24 @@ import { ThemeRegistryContext } from '../../../mol-theme/theme';
 import { Structure } from '../../../mol-model/structure';
 import { getUnitKindsParam } from '../params';
 import { ElementPointParams, ElementPointVisual } from '../visual/element-point';
+import { ElementCrossParams, ElementCrossVisual } from '../visual/element-cross';
 
 const LineVisuals = {
     'intra-bond': (ctx: RepresentationContext, getParams: RepresentationParamsGetter<Structure, IntraUnitBondLineParams>) => UnitsRepresentation('Intra-unit bond line', ctx, getParams, IntraUnitBondLineVisual),
     'inter-bond': (ctx: RepresentationContext, getParams: RepresentationParamsGetter<Structure, InterUnitBondLineParams>) => ComplexRepresentation('Inter-unit bond line', ctx, getParams, InterUnitBondLineVisual),
     'element-point': (ctx: RepresentationContext, getParams: RepresentationParamsGetter<Structure, ElementPointParams>) => UnitsRepresentation('Points', ctx, getParams, ElementPointVisual),
+    'element-cross': (ctx: RepresentationContext, getParams: RepresentationParamsGetter<Structure, ElementCrossParams>) => UnitsRepresentation('Crosses', ctx, getParams, ElementCrossVisual),
 };
 
 export const LineParams = {
     ...IntraUnitBondLineParams,
     ...InterUnitBondLineParams,
     ...ElementPointParams,
+    ...ElementCrossParams,
     includeParent: PD.Boolean(false),
     sizeFactor: PD.Numeric(3, { min: 0.01, max: 10, step: 0.01 }),
     unitKinds: getUnitKindsParam(['atomic']),
-    visuals: PD.MultiSelect(['intra-bond', 'inter-bond', 'element-point'], PD.objectToOptions(LineVisuals))
+    visuals: PD.MultiSelect(['intra-bond', 'inter-bond', 'element-point', 'element-cross'], PD.objectToOptions(LineVisuals))
 };
 export type LineParams = typeof LineParams
 export function getLineParams(ctx: ThemeRegistryContext, structure: Structure) {
@@ -46,7 +49,7 @@ export function LineRepresentation(ctx: RepresentationContext, getParams: Repres
 export const LineRepresentationProvider = StructureRepresentationProvider({
     name: 'line',
     label: 'Line',
-    description: 'Displays bonds as lines and atoms as points.',
+    description: 'Displays bonds as lines and atoms as points or croses.',
     factory: LineRepresentation,
     getParams: getLineParams,
     defaultValues: PD.getDefaultValues(LineParams),

+ 94 - 0
src/mol-repr/structure/visual/element-cross.ts

@@ -0,0 +1,94 @@
+/**
+ * Copyright (c) 2021 mol* contributors, licensed under MIT, See LICENSE file for more info.
+ *
+ * @author Alexander Rose <alexander.rose@weirdbyte.de>
+ */
+
+import { ParamDefinition as PD } from '../../../mol-util/param-definition';
+import { UnitsVisual, UnitsLinesParams, UnitsLinesVisual } from '../units-visual';
+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 { ElementIterator, getElementLoci, eachElement, makeElementIgnoreTest } from './util/element';
+import { VisualUpdateState } from '../../util';
+import { Sphere3D } from '../../../mol-math/geometry';
+import { Lines } from '../../../mol-geo/geometry/lines/lines';
+import { LinesBuilder } from '../../../mol-geo/geometry/lines/lines-builder';
+import { bondCount } from '../../../mol-model-props/computed/chemistry/util';
+
+// avoiding namespace lookup improved performance in Chrome (Aug 2020)
+const v3scaleAndAdd = Vec3.scaleAndAdd;
+const v3unitX = Vec3.unitX;
+const v3unitY = Vec3.unitY;
+const v3unitZ = Vec3.unitZ;
+
+export const ElementCrossParams = {
+    ...UnitsLinesParams,
+    lineSizeAttenuation: PD.Boolean(false),
+    ignoreHydrogens: PD.Boolean(false),
+    traceOnly: PD.Boolean(false),
+    crosses: PD.Select('lone', PD.arrayToOptions(['lone', 'all'] as const)),
+    crossSize: PD.Numeric(0.35, { min: 0, max: 2, step: 0.01 }),
+};
+export type ElementCrossParams = typeof ElementCrossParams
+
+export function createElementCross(ctx: VisualContext, unit: Unit, structure: Structure, theme: Theme, props: PD.Values<ElementCrossParams>, lines: Lines) {
+    const { child } = structure;
+    if (child && !child.unitMap.get(unit.id)) return Lines.createEmpty(lines);
+
+    const elements = unit.elements;
+    const n = elements.length;
+    const builder = LinesBuilder.create(n, n / 10, lines);
+
+    const p = Vec3();
+    const s = Vec3();
+    const e = Vec3();
+
+    const pos = unit.conformation.invariantPosition;
+    const ignore = makeElementIgnoreTest(structure, unit, props);
+
+    const r = props.crossSize / 2;
+    const lone = props.crosses === 'lone';
+
+    for (let i = 0 as StructureElement.UnitIndex; i < n; ++i) {
+        if (ignore && ignore(elements[i])) continue;
+        if (lone && Unit.isAtomic(unit) && bondCount(structure, unit, i) !== 0) continue;
+
+        pos(elements[i], p);
+        v3scaleAndAdd(s, p, v3unitX, r);
+        v3scaleAndAdd(e, p, v3unitX, -r);
+        builder.add(s[0], s[1], s[2], e[0], e[1], e[2], i);
+        v3scaleAndAdd(s, p, v3unitY, r);
+        v3scaleAndAdd(e, p, v3unitY, -r);
+        builder.add(s[0], s[1], s[2], e[0], e[1], e[2], i);
+        v3scaleAndAdd(s, p, v3unitZ, r);
+        v3scaleAndAdd(e, p, v3unitZ, -r);
+        builder.add(s[0], s[1], s[2], e[0], e[1], e[2], i);
+    }
+
+    const l = builder.getLines();
+
+    const sphere = Sphere3D.expand(Sphere3D(), unit.boundary.sphere, 1 * props.sizeFactor);
+    l.setBoundingSphere(sphere);
+
+    return l;
+}
+
+export function ElementCrossVisual(materialId: number): UnitsVisual<ElementCrossParams> {
+    return UnitsLinesVisual<ElementCrossParams>({
+        defaultProps: PD.getDefaultValues(ElementCrossParams),
+        createGeometry: createElementCross,
+        createLocationIterator: ElementIterator.fromGroup,
+        getLoci: getElementLoci,
+        eachLocation: eachElement,
+        setUpdateState: (state: VisualUpdateState, newProps: PD.Values<ElementCrossParams>, currentProps: PD.Values<ElementCrossParams>) => {
+            state.createGeometry = (
+                newProps.ignoreHydrogens !== currentProps.ignoreHydrogens ||
+                newProps.traceOnly !== currentProps.traceOnly ||
+                newProps.crosses !== currentProps.crosses ||
+                newProps.crossSize !== currentProps.crossSize
+            );
+        }
+    }, materialId);
+}