Browse Source

refactored bond & element ignore test

Alexander Rose 4 years ago
parent
commit
51dd388912

+ 3 - 14
src/mol-repr/structure/visual/bond-inter-unit-cylinder.ts

@@ -14,9 +14,8 @@ import { BitFlags, arrayEqual } from '../../../mol-util';
 import { createLinkCylinderMesh, LinkStyle } from './util/link';
 import { ComplexMeshParams, ComplexVisual, ComplexMeshVisual } from '../complex-visual';
 import { VisualUpdateState } from '../../util';
-import { isHydrogen } from './util/common';
 import { BondType } from '../../../mol-model/structure/model/types';
-import { ignoreBondType, BondCylinderParams, BondIterator, getInterBondLoci, eachInterBond } from './util/bond';
+import { BondCylinderParams, BondIterator, getInterBondLoci, eachInterBond, makeInterBondIgnoreTest } from './util/bond';
 
 const tmpRefPosBondIt = new Bond.ElementBondIterator();
 function setRefPosition(pos: Vec3, structure: Structure, unit: Unit.Atomic, index: StructureElement.UnitIndex) {
@@ -35,16 +34,7 @@ const tmpLoc = StructureElement.Location.create(void 0);
 function createInterUnitBondCylinderMesh(ctx: VisualContext, structure: Structure, theme: Theme, props: PD.Values<InterUnitBondCylinderParams>, mesh?: Mesh) {
     const bonds = structure.interUnitBonds;
     const { edgeCount, edges } = bonds;
-    const { sizeFactor, sizeAspectRatio, ignoreHydrogens, includeTypes, excludeTypes } = props;
-
-    const include = BondType.fromNames(includeTypes);
-    const exclude = BondType.fromNames(excludeTypes);
-
-    const ignoreHydrogen = ignoreHydrogens ? (edgeIndex: number) => {
-        const b = edges[edgeIndex];
-        const uA = b.unitA, uB = b.unitB;
-        return isHydrogen(uA, uA.elements[b.indexA]) || isHydrogen(uB, uB.elements[b.indexB]);
-    } : () => false;
+    const { sizeFactor, sizeAspectRatio } = props;
 
     if (!edgeCount) return Mesh.createEmpty(mesh);
 
@@ -96,7 +86,7 @@ function createInterUnitBondCylinderMesh(ctx: VisualContext, structure: Structur
             const sizeB = theme.size.size(tmpLoc);
             return Math.min(sizeA, sizeB) * sizeFactor * sizeAspectRatio;
         },
-        ignore: (edgeIndex: number) => ignoreHydrogen(edgeIndex) || ignoreBondType(include, exclude, edges[edgeIndex].props.flag)
+        ignore: makeInterBondIgnoreTest(structure, props)
     };
 
     return createLinkCylinderMesh(ctx, builderProps, props, mesh);
@@ -107,7 +97,6 @@ export const InterUnitBondCylinderParams = {
     ...BondCylinderParams,
     sizeFactor: PD.Numeric(0.3, { min: 0, max: 10, step: 0.01 }),
     sizeAspectRatio: PD.Numeric(2 / 3, { min: 0, max: 3, step: 0.01 }),
-    ignoreHydrogens: PD.Boolean(false),
 };
 export type InterUnitBondCylinderParams = typeof InterUnitBondCylinderParams
 

+ 3 - 14
src/mol-repr/structure/visual/bond-inter-unit-line.ts

@@ -13,9 +13,8 @@ import { BitFlags, arrayEqual } from '../../../mol-util';
 import { LinkStyle, createLinkLines } from './util/link';
 import { ComplexVisual, ComplexLinesVisual, ComplexLinesParams } from '../complex-visual';
 import { VisualUpdateState } from '../../util';
-import { isHydrogen } from './util/common';
 import { BondType } from '../../../mol-model/structure/model/types';
-import { ignoreBondType, BondIterator, getInterBondLoci, eachInterBond, BondLineParams } from './util/bond';
+import { BondIterator, getInterBondLoci, eachInterBond, BondLineParams, makeInterBondIgnoreTest } from './util/bond';
 import { Lines } from '../../../mol-geo/geometry/lines/lines';
 
 const tmpRefPosBondIt = new Bond.ElementBondIterator();
@@ -35,16 +34,7 @@ const tmpLoc = StructureElement.Location.create(void 0);
 function createInterUnitBondLines(ctx: VisualContext, structure: Structure, theme: Theme, props: PD.Values<InterUnitBondLineParams>, lines?: Lines) {
     const bonds = structure.interUnitBonds;
     const { edgeCount, edges } = bonds;
-    const { sizeFactor, ignoreHydrogens, includeTypes, excludeTypes } = props;
-
-    const include = BondType.fromNames(includeTypes);
-    const exclude = BondType.fromNames(excludeTypes);
-
-    const ignoreHydrogen = ignoreHydrogens ? (edgeIndex: number) => {
-        const b = edges[edgeIndex];
-        const uA = b.unitA, uB = b.unitB;
-        return isHydrogen(uA, uA.elements[b.indexA]) || isHydrogen(uB, uB.elements[b.indexB]);
-    } : () => false;
+    const { sizeFactor } = props;
 
     if (!edgeCount) return Lines.createEmpty(lines);
 
@@ -96,7 +86,7 @@ function createInterUnitBondLines(ctx: VisualContext, structure: Structure, them
             const sizeB = theme.size.size(tmpLoc);
             return Math.min(sizeA, sizeB) * sizeFactor;
         },
-        ignore: (edgeIndex: number) => ignoreHydrogen(edgeIndex) || ignoreBondType(include, exclude, edges[edgeIndex].props.flag)
+        ignore: makeInterBondIgnoreTest(structure, props)
     };
 
     return createLinkLines(ctx, builderProps, props, lines);
@@ -105,7 +95,6 @@ function createInterUnitBondLines(ctx: VisualContext, structure: Structure, them
 export const InterUnitBondLineParams = {
     ...ComplexLinesParams,
     ...BondLineParams,
-    ignoreHydrogens: PD.Boolean(false),
 };
 export type InterUnitBondLineParams = typeof InterUnitBondLineParams
 

+ 4 - 20
src/mol-repr/structure/visual/bond-intra-unit-cylinder.ts

@@ -15,9 +15,8 @@ import { arrayEqual } from '../../../mol-util';
 import { createLinkCylinderMesh, LinkStyle } from './util/link';
 import { UnitsMeshParams, UnitsVisual, UnitsMeshVisual, StructureGroup } from '../units-visual';
 import { VisualUpdateState } from '../../util';
-import { isHydrogen } from './util/common';
 import { BondType } from '../../../mol-model/structure/model/types';
-import { ignoreBondType, BondCylinderParams, BondIterator, eachIntraBond, getIntraBondLoci } from './util/bond';
+import { BondCylinderParams, BondIterator, eachIntraBond, getIntraBondLoci, makeIntraBondIgnoreTest } from './util/bond';
 import { Sphere3D } from '../../../mol-math/geometry';
 import { IntAdjacencyGraph } from '../../../mol-math/graph';
 
@@ -33,25 +32,11 @@ function createIntraUnitBondCylinderMesh(ctx: VisualContext, unit: Unit, structu
     const bonds = unit.bonds;
     const { edgeCount, a, b, edgeProps, offset } = bonds;
     const { order: _order, flags: _flags } = edgeProps;
-    const { sizeFactor, sizeAspectRatio, ignoreHydrogens, includeTypes, excludeTypes } = props;
-
-    const include = BondType.fromNames(includeTypes);
-    const exclude = BondType.fromNames(excludeTypes);
-
-    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]]);
-    }
+    const { sizeFactor, sizeAspectRatio } = props;
 
     if (!edgeCount) return Mesh.createEmpty(mesh);
 
-    const vRef = Vec3.zero();
+    const vRef = Vec3();
     const pos = unit.conformation.invariantPosition;
 
     const builderProps = {
@@ -98,7 +83,7 @@ function createIntraUnitBondCylinderMesh(ctx: VisualContext, unit: Unit, structu
             const sizeB = theme.size.size(location);
             return Math.min(sizeA, sizeB) * sizeFactor * sizeAspectRatio;
         },
-        ignore
+        ignore: makeIntraBondIgnoreTest(unit, props)
     };
 
     const m = createLinkCylinderMesh(ctx, builderProps, props, mesh);
@@ -114,7 +99,6 @@ export const IntraUnitBondCylinderParams = {
     ...BondCylinderParams,
     sizeFactor: PD.Numeric(0.3, { min: 0, max: 10, step: 0.01 }),
     sizeAspectRatio: PD.Numeric(2 / 3, { min: 0, max: 3, step: 0.01 }),
-    ignoreHydrogens: PD.Boolean(false),
 };
 export type IntraUnitBondCylinderParams = typeof IntraUnitBondCylinderParams
 

+ 4 - 20
src/mol-repr/structure/visual/bond-intra-unit-line.ts

@@ -13,9 +13,8 @@ import { arrayEqual } from '../../../mol-util';
 import { LinkStyle, createLinkLines } from './util/link';
 import { UnitsVisual, UnitsLinesParams, UnitsLinesVisual, StructureGroup } from '../units-visual';
 import { VisualUpdateState } from '../../util';
-import { isHydrogen } from './util/common';
 import { BondType } from '../../../mol-model/structure/model/types';
-import { ignoreBondType, BondIterator, BondLineParams, getIntraBondLoci, eachIntraBond } from './util/bond';
+import { BondIterator, BondLineParams, getIntraBondLoci, eachIntraBond, makeIntraBondIgnoreTest } from './util/bond';
 import { Sphere3D } from '../../../mol-math/geometry';
 import { Lines } from '../../../mol-geo/geometry/lines/lines';
 import { IntAdjacencyGraph } from '../../../mol-math/graph';
@@ -32,25 +31,11 @@ function createIntraUnitBondLines(ctx: VisualContext, unit: Unit, structure: Str
     const bonds = unit.bonds;
     const { edgeCount, a, b, edgeProps, offset } = bonds;
     const { order: _order, flags: _flags } = edgeProps;
-    const { sizeFactor, ignoreHydrogens, includeTypes, excludeTypes } = props;
-
-    const include = BondType.fromNames(includeTypes);
-    const exclude = BondType.fromNames(excludeTypes);
-
-    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]]);
-    }
+    const { sizeFactor } = props;
 
     if (!edgeCount) return Lines.createEmpty(lines);
 
-    const vRef = Vec3.zero();
+    const vRef = Vec3();
     const pos = unit.conformation.invariantPosition;
 
     const builderProps = {
@@ -97,7 +82,7 @@ function createIntraUnitBondLines(ctx: VisualContext, unit: Unit, structure: Str
             const sizeB = theme.size.size(location);
             return Math.min(sizeA, sizeB) * sizeFactor;
         },
-        ignore
+        ignore: makeIntraBondIgnoreTest(unit, props)
     };
 
     const l = createLinkLines(ctx, builderProps, props, lines);
@@ -111,7 +96,6 @@ function createIntraUnitBondLines(ctx: VisualContext, unit: Unit, structure: Str
 export const IntraUnitBondLineParams = {
     ...UnitsLinesParams,
     ...BondLineParams,
-    ignoreHydrogens: PD.Boolean(false),
 };
 export type IntraUnitBondLineParams = typeof IntraUnitBondLineParams
 

+ 15 - 10
src/mol-repr/structure/visual/element-point.ts

@@ -12,10 +12,9 @@ import { Theme } from '../../../mol-theme/theme';
 import { Points } from '../../../mol-geo/geometry/points/points';
 import { PointsBuilder } from '../../../mol-geo/geometry/points/points-builder';
 import { Vec3 } from '../../../mol-math/linear-algebra';
-import { ElementIterator, getElementLoci, eachElement } from './util/element';
+import { ElementIterator, getElementLoci, eachElement, makeElementIgnoreTest } from './util/element';
 import { VisualUpdateState } from '../../util';
 import { Sphere3D } from '../../../mol-math/geometry';
-import { isTrace, isHydrogen } from './util/common';
 
 export const ElementPointParams = {
     ...UnitsPointsParams,
@@ -29,21 +28,27 @@ export type ElementPointParams = typeof ElementPointParams
 // TODO size
 
 export function createElementPoint(ctx: VisualContext, unit: Unit, structure: Structure, theme: Theme, props: PD.Values<ElementPointParams>, points: Points) {
-    const { ignoreHydrogens, traceOnly } = props; // TODO sizeFactor
+    // TODO sizeFactor
 
     const elements = unit.elements;
     const n = elements.length;
     const builder = PointsBuilder.create(n, n / 10, points);
 
+    const p = Vec3();
     const pos = unit.conformation.invariantPosition;
-    const p = Vec3.zero();
+    const ignore = makeElementIgnoreTest(unit, props);
 
-    for (let i = 0; i < n; ++i) {
-        if (ignoreHydrogens && isHydrogen(unit, elements[i])) continue;
-        if (traceOnly && !isTrace(unit, elements[i])) continue;
-
-        pos(elements[i], p);
-        builder.add(p[0], p[1], p[2], i);
+    if (ignore) {
+        for (let i = 0; i < n; ++i) {
+            if (ignore(unit, elements[i])) continue;
+            pos(elements[i], p);
+            builder.add(p[0], p[1], p[2], i);
+        }
+    } else {
+        for (let i = 0; i < n; ++i) {
+            pos(elements[i], p);
+            builder.add(p[0], p[1], p[2], i);
+        }
     }
 
     const pt = builder.getPoints();

+ 51 - 0
src/mol-repr/structure/visual/util/bond.ts

@@ -14,10 +14,12 @@ import { ObjectKeys } from '../../../../mol-util/type-helpers';
 import { PickingId } from '../../../../mol-geo/geometry/picking';
 import { EmptyLoci, Loci } from '../../../../mol-model/loci';
 import { Interval, OrderedSet } from '../../../../mol-data/int';
+import { isH, isHydrogen } from './common';
 
 export const BondParams = {
     includeTypes: PD.MultiSelect(ObjectKeys(BondType.Names), PD.objectToOptions(BondType.Names)),
     excludeTypes: PD.MultiSelect([] as BondType.Names[], PD.objectToOptions(BondType.Names)),
+    ignoreHydrogens: PD.Boolean(false),
 };
 export const DefaultBondProps = PD.getDefaultValues(BondParams);
 export type BondProps = typeof DefaultBondProps
@@ -40,6 +42,55 @@ export function ignoreBondType(include: BondType.Flag, exclude: BondType.Flag, f
     return !BondType.is(include, f) || BondType.is(exclude, f);
 }
 
+export function makeIntraBondIgnoreTest(unit: Unit.Atomic, props: BondProps): undefined | ((edgeIndex: number) => boolean) {
+    const elements = unit.elements;
+    const { atomicNumber } = unit.model.atomicHierarchy.derived.atom;
+    const bonds = unit.bonds;
+    const { a, b, edgeProps } = bonds;
+    const { flags: _flags } = edgeProps;
+
+    const { ignoreHydrogens, includeTypes, excludeTypes } = props;
+
+    const include = BondType.fromNames(includeTypes);
+    const exclude = BondType.fromNames(excludeTypes);
+
+    const allBondTypes = BondType.isAll(include) && BondType.Flag.None === exclude;
+
+    if (!allBondTypes && ignoreHydrogens) {
+        return (edgeIndex: number) => isH(atomicNumber, elements[a[edgeIndex]]) || isH(atomicNumber, elements[b[edgeIndex]]) || ignoreBondType(include, exclude, _flags[edgeIndex]);
+    } else if (!allBondTypes) {
+        return (edgeIndex: number) => ignoreBondType(include, exclude, _flags[edgeIndex]);
+    } else if (ignoreHydrogens) {
+        return (edgeIndex: number) => isH(atomicNumber, elements[a[edgeIndex]]) || isH(atomicNumber, elements[b[edgeIndex]]);
+    }
+}
+
+export function makeInterBondIgnoreTest(structure: Structure, props: BondProps): undefined | ((edgeIndex: number) => boolean) {
+    const bonds = structure.interUnitBonds;
+    const { edges } = bonds;
+
+    const { ignoreHydrogens, includeTypes, excludeTypes } = props;
+
+    const include = BondType.fromNames(includeTypes);
+    const exclude = BondType.fromNames(excludeTypes);
+
+    const allBondTypes = BondType.isAll(include) && BondType.Flag.None === exclude;
+
+    const ignoreHydrogen = (edgeIndex: number) => {
+        const b = edges[edgeIndex];
+        const uA = b.unitA, uB = b.unitB;
+        return isHydrogen(uA, uA.elements[b.indexA]) || isHydrogen(uB, uB.elements[b.indexB]);
+    };
+
+    if (!allBondTypes && ignoreHydrogens) {
+        return (edgeIndex: number) => ignoreHydrogen(edgeIndex) || ignoreBondType(include, exclude, edges[edgeIndex].props.flag);
+    } else if (!allBondTypes) {
+        return (edgeIndex: number) => ignoreBondType(include, exclude, edges[edgeIndex].props.flag);
+    } else if (ignoreHydrogens) {
+        return (edgeIndex: number) => ignoreHydrogen(edgeIndex);
+    }
+}
+
 export namespace BondIterator {
     export function fromGroup(structureGroup: StructureGroup): LocationIterator {
         const { group, structure } = structureGroup;

+ 5 - 3
src/mol-repr/structure/visual/util/common.ts

@@ -10,7 +10,7 @@ import { TransformData, createTransform } from '../../../../mol-geo/geometry/tra
 import { OrderedSet, SortedArray } from '../../../../mol-data/int';
 import { EmptyLoci, Loci } from '../../../../mol-model/loci';
 import { PhysicalSizeTheme } from '../../../../mol-theme/size/physical';
-import { AtomicNumbers, AtomNumber } from '../../../../mol-model/structure/model/properties/atomic';
+import { AtomicNumbers } from '../../../../mol-model/structure/model/properties/atomic';
 import { fillSerial } from '../../../../mol-util/array';
 import { ParamDefinition as PD } from '../../../../mol-util/param-definition';
 import { AssignableArrayLike } from '../../../../mol-util/type-helpers';
@@ -269,8 +269,10 @@ export function getStructureConformationAndRadius(structure: Structure, ignoreHy
 const _H = AtomicNumbers['H'];
 export function isHydrogen(unit: Unit, element: ElementIndex) {
     if (Unit.isCoarse(unit)) return false;
-    if (AtomNumber(unit.model.atomicHierarchy.atoms.type_symbol.value(element)) === _H) return true;
-    return false;
+    return unit.model.atomicHierarchy.derived.atom.atomicNumber[element] === _H;
+}
+export function isH(atomicNumber: ArrayLike<number>, element: ElementIndex) {
+    return atomicNumber[element] === _H;
 }
 
 export function isTrace(unit: Unit, element: ElementIndex) {

+ 41 - 22
src/mol-repr/structure/visual/util/element.ts

@@ -6,7 +6,7 @@
  */
 
 import { Vec3 } from '../../../../mol-math/linear-algebra';
-import { Unit, StructureElement, Structure } from '../../../../mol-model/structure';
+import { Unit, StructureElement, Structure, ElementIndex } from '../../../../mol-model/structure';
 import { Loci, EmptyLoci } from '../../../../mol-model/loci';
 import { Interval, OrderedSet } from '../../../../mol-data/int';
 import { Mesh } from '../../../../mol-geo/geometry/mesh/mesh';
@@ -20,32 +20,50 @@ import { Theme } from '../../../../mol-theme/theme';
 import { StructureGroup } from '../../../../mol-repr/structure/units-visual';
 import { Spheres } from '../../../../mol-geo/geometry/spheres/spheres';
 import { SpheresBuilder } from '../../../../mol-geo/geometry/spheres/spheres-builder';
-import { isHydrogen, isTrace } from './common';
+import { isTrace, isH } from './common';
 import { Sphere3D } from '../../../../mol-math/geometry';
 
-export interface ElementSphereMeshProps {
-    detail: number,
-    sizeFactor: number,
+type ElementProps = {
     ignoreHydrogens: boolean,
     traceOnly: boolean,
 }
 
+export type ElementSphereMeshProps = {
+    detail: number,
+    sizeFactor: number,
+} & ElementProps
+
+export function makeElementIgnoreTest(unit: Unit, props: ElementProps): undefined | ((unit: Unit, i: ElementIndex) => boolean) {
+    const { ignoreHydrogens, traceOnly } = props;
+
+    const { atomicNumber } = unit.model.atomicHierarchy.derived.atom;
+    const isCoarse = Unit.isCoarse(unit);
+
+    if (!isCoarse && ignoreHydrogens && traceOnly) {
+        return (unit: Unit, element: ElementIndex) => isH(atomicNumber, element) && !isTrace(unit, element);
+    } else if (!isCoarse && ignoreHydrogens) {
+        return (unit: Unit, element: ElementIndex) => isH(atomicNumber, element);
+    } else if (!isCoarse && traceOnly) {
+        return (unit: Unit, element: ElementIndex) => !isTrace(unit, element);
+    }
+}
+
 export function createElementSphereMesh(ctx: VisualContext, unit: Unit, structure: Structure, theme: Theme, props: ElementSphereMeshProps, mesh?: Mesh): Mesh {
-    const { detail, sizeFactor, ignoreHydrogens, traceOnly } = props;
+    const { detail, sizeFactor } = props;
 
     const { elements } = unit;
     const elementCount = elements.length;
     const vertexCount = elementCount * sphereVertexCount(detail);
     const builderState = MeshBuilder.createState(vertexCount, vertexCount / 2, mesh);
 
-    const v = Vec3.zero();
+    const v = Vec3();
     const pos = unit.conformation.invariantPosition;
+    const ignore = makeElementIgnoreTest(unit, props);
     const l = StructureElement.Location.create(structure);
     l.unit = unit;
 
     for (let i = 0; i < elementCount; i++) {
-        if (ignoreHydrogens && isHydrogen(unit, elements[i])) continue;
-        if (traceOnly && !isTrace(unit, elements[i])) continue;
+        if (ignore && ignore(unit, elements[i])) continue;
 
         l.element = elements[i];
         pos(elements[i], v);
@@ -62,27 +80,28 @@ export function createElementSphereMesh(ctx: VisualContext, unit: Unit, structur
     return m;
 }
 
-export interface ElementSphereImpostorProps {
-    ignoreHydrogens: boolean,
-    traceOnly: boolean
-}
+export type ElementSphereImpostorProps = ElementProps
 
 export function createElementSphereImpostor(ctx: VisualContext, unit: Unit, structure: Structure, theme: Theme, props: ElementSphereImpostorProps, spheres?: Spheres): Spheres {
-    const { ignoreHydrogens, traceOnly } = props;
-
     const { elements } = unit;
     const elementCount = elements.length;
     const builder = SpheresBuilder.create(elementCount, elementCount / 2, spheres);
 
-    const v = Vec3.zero();
+    const v = Vec3();
     const pos = unit.conformation.invariantPosition;
+    const ignore = makeElementIgnoreTest(unit, props);
 
-    for (let i = 0; i < elementCount; i++) {
-        if (ignoreHydrogens && isHydrogen(unit, elements[i])) continue;
-        if (traceOnly && !isTrace(unit, elements[i])) continue;
-
-        pos(elements[i], v);
-        builder.add(v[0], v[1], v[2], i);
+    if (ignore) {
+        for (let i = 0; i < elementCount; i++) {
+            if (ignore(unit, elements[i])) continue;
+            pos(elements[i], v);
+            builder.add(v[0], v[1], v[2], i);
+        }
+    } else {
+        for (let i = 0; i < elementCount; i++) {
+            pos(elements[i], v);
+            builder.add(v[0], v[1], v[2], i);
+        }
     }
 
     const s = builder.getSpheres();