mirror of
https://github.com/molstar/molstar.git
synced 2026-06-06 06:34:23 +08:00
Compare commits
4 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d5ed3aa674 | ||
|
|
cfb9c9acfe | ||
|
|
67feef0b1d | ||
|
|
e0192ab5aa |
@@ -6,6 +6,11 @@ Note that since we don't clearly distinguish between a public and private interf
|
||||
|
||||
## [Unreleased]
|
||||
|
||||
## [v3.3.1] - 2022-02-27
|
||||
|
||||
- Fix issue with unit boundary reuse (do at visual level instead)
|
||||
- Add option to ignore ions for inter-unit bond computation
|
||||
|
||||
## [v3.3.0] - 2022-02-27
|
||||
|
||||
- Fix parsing contour-level from emdb v3 header files
|
||||
|
||||
4
package-lock.json
generated
4
package-lock.json
generated
@@ -1,12 +1,12 @@
|
||||
{
|
||||
"name": "molstar",
|
||||
"version": "3.3.0",
|
||||
"version": "3.3.1",
|
||||
"lockfileVersion": 2,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "molstar",
|
||||
"version": "3.3.0",
|
||||
"version": "3.3.1",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@types/argparse": "^2.0.10",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "molstar",
|
||||
"version": "3.3.0",
|
||||
"version": "3.3.1",
|
||||
"description": "A comprehensive macromolecular library.",
|
||||
"homepage": "https://github.com/molstar/molstar#readme",
|
||||
"repository": {
|
||||
|
||||
@@ -55,7 +55,16 @@ function createIntraUnitClashCylinderMesh(ctx: VisualContext, unit: Unit, struct
|
||||
radius: (edgeIndex: number) => magnitude[edgeIndex] * sizeFactor,
|
||||
};
|
||||
|
||||
return createLinkCylinderMesh(ctx, builderProps, props, mesh);
|
||||
const { mesh: m, boundingSphere } = createLinkCylinderMesh(ctx, builderProps, props, mesh);
|
||||
|
||||
if (boundingSphere) {
|
||||
m.setBoundingSphere(boundingSphere);
|
||||
} else if (m.triangleCount > 0) {
|
||||
const sphere = Sphere3D.expand(Sphere3D(), structure.boundary.sphere, 1 * sizeFactor);
|
||||
m.setBoundingSphere(sphere);
|
||||
}
|
||||
|
||||
return m;
|
||||
}
|
||||
|
||||
export const IntraUnitClashParams = {
|
||||
@@ -169,7 +178,16 @@ function createInterUnitClashCylinderMesh(ctx: VisualContext, structure: Structu
|
||||
radius: (edgeIndex: number) => edges[edgeIndex].props.magnitude * sizeFactor
|
||||
};
|
||||
|
||||
return createLinkCylinderMesh(ctx, builderProps, props, mesh);
|
||||
const { mesh: m, boundingSphere } = createLinkCylinderMesh(ctx, builderProps, props, mesh);
|
||||
|
||||
if (boundingSphere) {
|
||||
m.setBoundingSphere(boundingSphere);
|
||||
} else {
|
||||
const sphere = Sphere3D.expand(Sphere3D(), structure.boundary.sphere, 1 * sizeFactor);
|
||||
m.setBoundingSphere(sphere);
|
||||
}
|
||||
|
||||
return m;
|
||||
}
|
||||
|
||||
export const InterUnitClashParams = {
|
||||
|
||||
@@ -85,10 +85,15 @@ function createInterUnitInteractionCylinderMesh(ctx: VisualContext, structure: S
|
||||
}
|
||||
};
|
||||
|
||||
const m = createLinkCylinderMesh(ctx, builderProps, props, mesh);
|
||||
const { mesh: m, boundingSphere } = createLinkCylinderMesh(ctx, builderProps, props, mesh);
|
||||
|
||||
const sphere = Sphere3D.expand(Sphere3D(), (child ?? structure).boundary.sphere, 1 * sizeFactor);
|
||||
m.setBoundingSphere(sphere);
|
||||
if (boundingSphere) {
|
||||
m.setBoundingSphere(boundingSphere);
|
||||
} else if (m.triangleCount > 0) {
|
||||
const { child } = structure;
|
||||
const sphere = Sphere3D.expand(Sphere3D(), (child ?? structure).boundary.sphere, 1 * sizeFactor);
|
||||
m.setBoundingSphere(sphere);
|
||||
}
|
||||
|
||||
return m;
|
||||
}
|
||||
|
||||
@@ -71,10 +71,14 @@ async function createIntraUnitInteractionsCylinderMesh(ctx: VisualContext, unit:
|
||||
}
|
||||
};
|
||||
|
||||
const m = createLinkCylinderMesh(ctx, builderProps, props, mesh);
|
||||
const { mesh: m, boundingSphere } = createLinkCylinderMesh(ctx, builderProps, props, mesh);
|
||||
|
||||
const sphere = Sphere3D.expand(Sphere3D(), (childUnit ?? unit).boundary.sphere, 1 * sizeFactor);
|
||||
m.setBoundingSphere(sphere);
|
||||
if (boundingSphere) {
|
||||
m.setBoundingSphere(boundingSphere);
|
||||
} else if (m.triangleCount > 0) {
|
||||
const sphere = Sphere3D.expand(Sphere3D(), (childUnit ?? unit).boundary.sphere, 1 * sizeFactor);
|
||||
m.setBoundingSphere(sphere);
|
||||
}
|
||||
|
||||
return m;
|
||||
}
|
||||
|
||||
@@ -22,6 +22,7 @@ import { VisualUpdateState } from '../../../mol-repr/util';
|
||||
import { ComplexRepresentation, StructureRepresentation, StructureRepresentationStateBuilder, StructureRepresentationProvider } from '../../../mol-repr/structure/representation';
|
||||
import { CustomProperty } from '../../common/custom-property';
|
||||
import { CrossLinkRestraintProvider, CrossLinkRestraint } from './property';
|
||||
import { Sphere3D } from '../../../mol-math/geometry';
|
||||
|
||||
function createCrossLinkRestraintCylinderMesh(ctx: VisualContext, structure: Structure, theme: Theme, props: PD.Values<CrossLinkRestraintCylinderParams>, mesh?: Mesh) {
|
||||
|
||||
@@ -47,7 +48,16 @@ function createCrossLinkRestraintCylinderMesh(ctx: VisualContext, structure: Str
|
||||
},
|
||||
};
|
||||
|
||||
return createLinkCylinderMesh(ctx, builderProps, props, mesh);
|
||||
const { mesh: m, boundingSphere } = createLinkCylinderMesh(ctx, builderProps, props, mesh);
|
||||
|
||||
if (boundingSphere) {
|
||||
m.setBoundingSphere(boundingSphere);
|
||||
} else if (m.triangleCount > 0) {
|
||||
const sphere = Sphere3D.expand(Sphere3D(), structure.boundary.sphere, 1 * sizeFactor);
|
||||
m.setBoundingSphere(sphere);
|
||||
}
|
||||
|
||||
return m;
|
||||
}
|
||||
|
||||
export const CrossLinkRestraintCylinderParams = {
|
||||
|
||||
@@ -238,7 +238,10 @@ class Structure {
|
||||
// no need to compute InterUnitBonds if parent's ones are empty
|
||||
this.state.interUnitBonds = new InterUnitBonds(new Map());
|
||||
} else {
|
||||
this.state.interUnitBonds = computeInterUnitBonds(this, { ignoreWater: !this.dynamicBonds });
|
||||
this.state.interUnitBonds = computeInterUnitBonds(this, {
|
||||
ignoreWater: !this.dynamicBonds,
|
||||
ignoreIon: !this.dynamicBonds,
|
||||
});
|
||||
}
|
||||
return this.state.interUnitBonds;
|
||||
}
|
||||
|
||||
@@ -27,9 +27,6 @@ import { ElementSetIntraBondCache } from './unit/bonds/element-set-intra-bond-ca
|
||||
import { ModelSymmetry } from '../../../mol-model-formats/structure/property/symmetry';
|
||||
import { getResonance, UnitResonance } from './unit/resonance';
|
||||
|
||||
// avoiding namespace lookup improved performance in Chrome (Aug 2020)
|
||||
const v3add = Vec3.add;
|
||||
|
||||
/**
|
||||
* A building block of a structure that corresponds to an atomic or
|
||||
* a coarse grained representation 'conveniently grouped together'.
|
||||
@@ -231,25 +228,7 @@ namespace Unit {
|
||||
: tryRemapBonds(this, this.props.bonds, model, dynamicBonds)
|
||||
};
|
||||
if (!Unit.isSameConformation(this, model)) {
|
||||
const b = props.boundary;
|
||||
if (b) {
|
||||
const { elements } = this;
|
||||
const pos = this.conformation.invariantPosition;
|
||||
const v = Vec3();
|
||||
const center = Vec3();
|
||||
|
||||
for (let i = 0, il = elements.length; i < il; i++) {
|
||||
pos(elements[i], v);
|
||||
v3add(center, center, v);
|
||||
}
|
||||
Vec3.scale(center, center, 1 / elements.length);
|
||||
|
||||
// only invalidate boundary if sphere has changed too much
|
||||
if (Vec3.distance(center, b.sphere.center) / b.sphere.radius >= 1.0) {
|
||||
props.boundary = undefined;
|
||||
}
|
||||
}
|
||||
|
||||
props.boundary = undefined;
|
||||
props.lookup3d = undefined;
|
||||
props.principalAxes = undefined;
|
||||
}
|
||||
|
||||
@@ -193,11 +193,13 @@ function findPairBonds(unitA: Unit.Atomic, unitB: Unit.Atomic, props: BondComput
|
||||
export interface InterBondComputationProps extends BondComputationProps {
|
||||
validUnitPair: (structure: Structure, unitA: Unit, unitB: Unit) => boolean
|
||||
ignoreWater: boolean
|
||||
ignoreIon: boolean
|
||||
}
|
||||
|
||||
const DefaultInterBondComputationProps = {
|
||||
...DefaultBondComputationProps,
|
||||
ignoreWater: true
|
||||
ignoreWater: true,
|
||||
ignoreIon: true,
|
||||
};
|
||||
|
||||
function findBonds(structure: Structure, props: InterBondComputationProps) {
|
||||
@@ -233,7 +235,11 @@ function computeInterUnitBonds(structure: Structure, props?: Partial<InterBondCo
|
||||
(!Unit.isAtomic(a) || mtA[a.residueIndex[a.elements[0]]] !== MoleculeType.Water) &&
|
||||
(!Unit.isAtomic(b) || mtB[b.residueIndex[b.elements[0]]] !== MoleculeType.Water)
|
||||
);
|
||||
return Structure.validUnitPair(s, a, b) && (notWater || !p.ignoreWater);
|
||||
const notIon = (
|
||||
(!Unit.isAtomic(a) || mtA[a.residueIndex[a.elements[0]]] !== MoleculeType.Ion) &&
|
||||
(!Unit.isAtomic(b) || mtB[b.residueIndex[b.elements[0]]] !== MoleculeType.Ion)
|
||||
);
|
||||
return Structure.validUnitPair(s, a, b) && (notWater || !p.ignoreWater) && (notIon || !p.ignoreIon);
|
||||
}),
|
||||
});
|
||||
}
|
||||
|
||||
@@ -17,7 +17,7 @@ import { PluginStateObject as SO } from '../objects';
|
||||
import { ModelSymmetry } from '../../mol-model-formats/structure/property/symmetry';
|
||||
|
||||
const CommonStructureParams = {
|
||||
dynamicBonds: PD.Optional(PD.Boolean(false, { description: 'Ensure bonds are recalculated upon model changes. Also enables calculation of inter-unit bonds in water molecules.' })),
|
||||
dynamicBonds: PD.Optional(PD.Boolean(false, { description: 'Ensure bonds are recalculated upon model changes. Also enables calculation of inter-unit bonds in water molecules and ions.' })),
|
||||
};
|
||||
type CommonStructureProps = PD.ValuesFor<typeof CommonStructureParams>
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* Copyright (c) 2018-2021 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
* Copyright (c) 2018-2022 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
*
|
||||
* @author Alexander Rose <alexander.rose@weirdbyte.de>
|
||||
*/
|
||||
@@ -162,24 +162,32 @@ function createInterUnitBondCylinderImpostors(ctx: VisualContext, structure: Str
|
||||
if (!structure.interUnitBonds.edgeCount) return Cylinders.createEmpty(cylinders);
|
||||
|
||||
const builderProps = getInterUnitBondCylinderBuilderProps(structure, theme, props);
|
||||
const m = createLinkCylinderImpostors(ctx, builderProps, props, cylinders);
|
||||
const { cylinders: c, boundingSphere } = createLinkCylinderImpostors(ctx, builderProps, props, cylinders);
|
||||
|
||||
const { child } = structure;
|
||||
const sphere = Sphere3D.expand(Sphere3D(), (child ?? structure).boundary.sphere, 1 * props.sizeFactor);
|
||||
m.setBoundingSphere(sphere);
|
||||
if (boundingSphere) {
|
||||
c.setBoundingSphere(boundingSphere);
|
||||
} else if (c.cylinderCount > 0) {
|
||||
const { child } = structure;
|
||||
const sphere = Sphere3D.expand(Sphere3D(), (child ?? structure).boundary.sphere, 1 * props.sizeFactor);
|
||||
c.setBoundingSphere(sphere);
|
||||
}
|
||||
|
||||
return m;
|
||||
return c;
|
||||
}
|
||||
|
||||
function createInterUnitBondCylinderMesh(ctx: VisualContext, structure: Structure, theme: Theme, props: PD.Values<InterUnitBondCylinderParams>, mesh?: Mesh) {
|
||||
if (!structure.interUnitBonds.edgeCount) return Mesh.createEmpty(mesh);
|
||||
|
||||
const builderProps = getInterUnitBondCylinderBuilderProps(structure, theme, props);
|
||||
const m = createLinkCylinderMesh(ctx, builderProps, props, mesh);
|
||||
const { mesh: m, boundingSphere } = createLinkCylinderMesh(ctx, builderProps, props, mesh);
|
||||
|
||||
const { child } = structure;
|
||||
const sphere = Sphere3D.expand(Sphere3D(), (child ?? structure).boundary.sphere, 1 * props.sizeFactor);
|
||||
m.setBoundingSphere(sphere);
|
||||
if (boundingSphere) {
|
||||
m.setBoundingSphere(boundingSphere);
|
||||
} else if (m.triangleCount > 0) {
|
||||
const { child } = structure;
|
||||
const sphere = Sphere3D.expand(Sphere3D(), (child ?? structure).boundary.sphere, 1 * props.sizeFactor);
|
||||
m.setBoundingSphere(sphere);
|
||||
}
|
||||
|
||||
return m;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* Copyright (c) 2020-2021 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
* Copyright (c) 2020-2022 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
*
|
||||
* @author Alexander Rose <alexander.rose@weirdbyte.de>
|
||||
*/
|
||||
@@ -103,11 +103,15 @@ function createInterUnitBondLines(ctx: VisualContext, structure: Structure, them
|
||||
ignore: makeInterBondIgnoreTest(structure, props)
|
||||
};
|
||||
|
||||
const l = createLinkLines(ctx, builderProps, props, lines);
|
||||
const { lines: l, boundingSphere } = createLinkLines(ctx, builderProps, props, lines);
|
||||
|
||||
const { child } = structure;
|
||||
const sphere = Sphere3D.expand(Sphere3D(), (child ?? structure).boundary.sphere, 1 * props.sizeFactor);
|
||||
l.setBoundingSphere(sphere);
|
||||
if (boundingSphere) {
|
||||
l.setBoundingSphere(boundingSphere);
|
||||
} else if (l.lineCount > 0) {
|
||||
const { child } = structure;
|
||||
const sphere = Sphere3D.expand(Sphere3D(), (child ?? structure).boundary.sphere, 1 * sizeFactor);
|
||||
l.setBoundingSphere(sphere);
|
||||
}
|
||||
|
||||
return l;
|
||||
}
|
||||
|
||||
@@ -178,10 +178,14 @@ function createIntraUnitBondCylinderImpostors(ctx: VisualContext, unit: Unit, st
|
||||
if (child && !childUnit) return Cylinders.createEmpty(cylinders);
|
||||
|
||||
const builderProps = getIntraUnitBondCylinderBuilderProps(unit, structure, theme, props);
|
||||
const c = createLinkCylinderImpostors(ctx, builderProps, props, cylinders);
|
||||
const { cylinders: c, boundingSphere } = createLinkCylinderImpostors(ctx, builderProps, props, cylinders);
|
||||
|
||||
const sphere = Sphere3D.expand(Sphere3D(), (childUnit ?? unit).boundary.sphere, 1 * props.sizeFactor);
|
||||
c.setBoundingSphere(sphere);
|
||||
if (boundingSphere) {
|
||||
c.setBoundingSphere(boundingSphere);
|
||||
} else if (c.cylinderCount > 0) {
|
||||
const sphere = Sphere3D.expand(Sphere3D(), (childUnit ?? unit).boundary.sphere, 1 * props.sizeFactor);
|
||||
c.setBoundingSphere(sphere);
|
||||
}
|
||||
|
||||
return c;
|
||||
}
|
||||
@@ -195,10 +199,14 @@ function createIntraUnitBondCylinderMesh(ctx: VisualContext, unit: Unit, structu
|
||||
if (child && !childUnit) return Mesh.createEmpty(mesh);
|
||||
|
||||
const builderProps = getIntraUnitBondCylinderBuilderProps(unit, structure, theme, props);
|
||||
const m = createLinkCylinderMesh(ctx, builderProps, props, mesh);
|
||||
const { mesh: m, boundingSphere } = createLinkCylinderMesh(ctx, builderProps, props, mesh);
|
||||
|
||||
const sphere = Sphere3D.expand(Sphere3D(), (childUnit ?? unit).boundary.sphere, 1 * props.sizeFactor);
|
||||
m.setBoundingSphere(sphere);
|
||||
if (boundingSphere) {
|
||||
m.setBoundingSphere(boundingSphere);
|
||||
} else if (m.triangleCount > 0) {
|
||||
const sphere = Sphere3D.expand(Sphere3D(), (childUnit ?? unit).boundary.sphere, 1 * props.sizeFactor);
|
||||
m.setBoundingSphere(sphere);
|
||||
}
|
||||
|
||||
return m;
|
||||
}
|
||||
|
||||
@@ -132,10 +132,14 @@ function createIntraUnitBondLines(ctx: VisualContext, unit: Unit, structure: Str
|
||||
ignore: makeIntraBondIgnoreTest(structure, unit, props)
|
||||
};
|
||||
|
||||
const l = createLinkLines(ctx, builderProps, props, lines);
|
||||
const { lines: l, boundingSphere } = createLinkLines(ctx, builderProps, props, lines);
|
||||
|
||||
const sphere = Sphere3D.expand(Sphere3D(), (childUnit ?? unit).boundary.sphere, 1 * sizeFactor);
|
||||
l.setBoundingSphere(sphere);
|
||||
if (boundingSphere) {
|
||||
l.setBoundingSphere(boundingSphere);
|
||||
} else if (l.lineCount > 0) {
|
||||
const sphere = Sphere3D.expand(Sphere3D(), (childUnit ?? unit).boundary.sphere, 1 * sizeFactor);
|
||||
l.setBoundingSphere(sphere);
|
||||
}
|
||||
|
||||
return l;
|
||||
}
|
||||
|
||||
@@ -19,6 +19,7 @@ import { VisualUpdateState } from '../../util';
|
||||
import { VisualContext } from '../../../mol-repr/visual';
|
||||
import { Theme } from '../../../mol-theme/theme';
|
||||
import { getAltResidueLociFromId } from './util/common';
|
||||
import { Sphere3D } from '../../../mol-math/geometry';
|
||||
|
||||
function createCarbohydrateLinkCylinderMesh(ctx: VisualContext, structure: Structure, theme: Theme, props: PD.Values<CarbohydrateLinkParams>, mesh?: Mesh) {
|
||||
const { links, elements } = structure.carbohydrates;
|
||||
@@ -43,7 +44,16 @@ function createCarbohydrateLinkCylinderMesh(ctx: VisualContext, structure: Struc
|
||||
},
|
||||
};
|
||||
|
||||
return createLinkCylinderMesh(ctx, builderProps, props, mesh);
|
||||
const { mesh: m, boundingSphere } = createLinkCylinderMesh(ctx, builderProps, props, mesh);
|
||||
|
||||
if (boundingSphere) {
|
||||
m.setBoundingSphere(boundingSphere);
|
||||
} else if (m.triangleCount > 0) {
|
||||
const sphere = Sphere3D.expand(Sphere3D(), structure.boundary.sphere, 1 * linkSizeFactor);
|
||||
m.setBoundingSphere(sphere);
|
||||
}
|
||||
|
||||
return m;
|
||||
}
|
||||
|
||||
export const CarbohydrateLinkParams = {
|
||||
|
||||
@@ -20,6 +20,7 @@ import { PickingId } from '../../../mol-geo/geometry/picking';
|
||||
import { EmptyLoci, Loci } from '../../../mol-model/loci';
|
||||
import { getElementIdx, MetalsSet } from '../../../mol-model/structure/structure/unit/bonds/common';
|
||||
import { getAltResidueLociFromId, getAltResidueLoci } from './util/common';
|
||||
import { Sphere3D } from '../../../mol-math/geometry';
|
||||
|
||||
function createCarbohydrateTerminalLinkCylinderMesh(ctx: VisualContext, structure: Structure, theme: Theme, props: PD.Values<CarbohydrateTerminalLinkParams>, mesh?: Mesh) {
|
||||
const { terminalLinks, elements } = structure.carbohydrates;
|
||||
@@ -60,7 +61,16 @@ function createCarbohydrateTerminalLinkCylinderMesh(ctx: VisualContext, structur
|
||||
}
|
||||
};
|
||||
|
||||
return createLinkCylinderMesh(ctx, builderProps, props, mesh);
|
||||
const { mesh: m, boundingSphere } = createLinkCylinderMesh(ctx, builderProps, props, mesh);
|
||||
|
||||
if (boundingSphere) {
|
||||
m.setBoundingSphere(boundingSphere);
|
||||
} else if (m.triangleCount > 0) {
|
||||
const sphere = Sphere3D.expand(Sphere3D(), structure.boundary.sphere, 1 * terminalLinkSizeFactor);
|
||||
m.setBoundingSphere(sphere);
|
||||
}
|
||||
|
||||
return m;
|
||||
}
|
||||
|
||||
export const CarbohydrateTerminalLinkParams = {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* Copyright (c) 2018-2021 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
* Copyright (c) 2018-2022 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
*
|
||||
* @author Alexander Rose <alexander.rose@weirdbyte.de>
|
||||
*/
|
||||
@@ -16,6 +16,9 @@ import { ElementIterator, getElementLoci, eachElement, makeElementIgnoreTest } f
|
||||
import { VisualUpdateState } from '../../util';
|
||||
import { Sphere3D } from '../../../mol-math/geometry';
|
||||
|
||||
// avoiding namespace lookup improved performance in Chrome (Aug 2020)
|
||||
const v3add = Vec3.add;
|
||||
|
||||
export const ElementPointParams = {
|
||||
...UnitsPointsParams,
|
||||
pointSizeAttenuation: PD.Boolean(false),
|
||||
@@ -39,24 +42,39 @@ export function createElementPoint(ctx: VisualContext, unit: Unit, structure: St
|
||||
const p = Vec3();
|
||||
const pos = unit.conformation.invariantPosition;
|
||||
const ignore = makeElementIgnoreTest(structure, unit, props);
|
||||
const center = Vec3();
|
||||
let count = 0;
|
||||
|
||||
if (ignore) {
|
||||
for (let i = 0; i < n; ++i) {
|
||||
if (ignore(elements[i])) continue;
|
||||
pos(elements[i], p);
|
||||
v3add(center, center, p);
|
||||
count += 1;
|
||||
builder.add(p[0], p[1], p[2], i);
|
||||
}
|
||||
} else {
|
||||
for (let i = 0; i < n; ++i) {
|
||||
pos(elements[i], p);
|
||||
v3add(center, center, p);
|
||||
count += 1;
|
||||
builder.add(p[0], p[1], p[2], i);
|
||||
}
|
||||
}
|
||||
|
||||
const oldBoundingSphere = points ? Sphere3D.clone(points.boundingSphere) : undefined;
|
||||
const pt = builder.getPoints();
|
||||
if (count === 0) return pt;
|
||||
|
||||
const sphere = Sphere3D.expand(Sphere3D(), unit.boundary.sphere, 1 * props.sizeFactor);
|
||||
pt.setBoundingSphere(sphere);
|
||||
// re-use boundingSphere if it has not changed much
|
||||
let boundingSphere: Sphere3D;
|
||||
Vec3.scale(center, center, 1 / count);
|
||||
if (oldBoundingSphere && Vec3.distance(center, oldBoundingSphere.center) / oldBoundingSphere.radius < 1.0) {
|
||||
boundingSphere = oldBoundingSphere;
|
||||
} else {
|
||||
boundingSphere = Sphere3D.expand(Sphere3D(), unit.boundary.sphere, 1 * props.sizeFactor);
|
||||
}
|
||||
pt.setBoundingSphere(boundingSphere);
|
||||
|
||||
return pt;
|
||||
}
|
||||
|
||||
@@ -22,6 +22,9 @@ import { SpheresBuilder } from '../../../../mol-geo/geometry/spheres/spheres-bui
|
||||
import { isTrace, isH, StructureGroup } from './common';
|
||||
import { Sphere3D } from '../../../../mol-math/geometry';
|
||||
|
||||
// avoiding namespace lookup improved performance in Chrome (Aug 2020)
|
||||
const v3add = Vec3.add;
|
||||
|
||||
type ElementProps = {
|
||||
ignoreHydrogens: boolean,
|
||||
traceOnly: boolean,
|
||||
@@ -70,13 +73,17 @@ export function createElementSphereMesh(ctx: VisualContext, unit: Unit, structur
|
||||
const ignore = makeElementIgnoreTest(structure, unit, props);
|
||||
const l = StructureElement.Location.create(structure, unit);
|
||||
const themeSize = theme.size.size;
|
||||
const center = Vec3();
|
||||
let maxSize = 0;
|
||||
let count = 0;
|
||||
|
||||
for (let i = 0; i < elementCount; i++) {
|
||||
if (ignore && ignore(elements[i])) continue;
|
||||
|
||||
l.element = elements[i];
|
||||
pos(elements[i], v);
|
||||
v3add(center, center, v);
|
||||
count += 1;
|
||||
|
||||
builderState.currentGroup = i;
|
||||
const size = themeSize(l);
|
||||
@@ -85,8 +92,19 @@ export function createElementSphereMesh(ctx: VisualContext, unit: Unit, structur
|
||||
addSphere(builderState, v, size * sizeFactor, detail);
|
||||
}
|
||||
|
||||
const oldBoundingSphere = mesh ? Sphere3D.clone(mesh.boundingSphere) : undefined;
|
||||
const m = MeshBuilder.getMesh(builderState);
|
||||
m.setBoundingSphere(Sphere3D.expand(Sphere3D(), (childUnit ?? unit).boundary.sphere, maxSize * sizeFactor + 0.05));
|
||||
if (count === 0) return m;
|
||||
|
||||
// re-use boundingSphere if it has not changed much
|
||||
let boundingSphere: Sphere3D;
|
||||
Vec3.scale(center, center, 1 / count);
|
||||
if (oldBoundingSphere && Vec3.distance(center, oldBoundingSphere.center) / oldBoundingSphere.radius < 1.0) {
|
||||
boundingSphere = oldBoundingSphere;
|
||||
} else {
|
||||
boundingSphere = Sphere3D.expand(Sphere3D(), (childUnit ?? unit).boundary.sphere, maxSize * sizeFactor + 0.05);
|
||||
}
|
||||
m.setBoundingSphere(boundingSphere);
|
||||
|
||||
return m;
|
||||
}
|
||||
@@ -110,21 +128,36 @@ export function createElementSphereImpostor(ctx: VisualContext, unit: Unit, stru
|
||||
|
||||
const l = StructureElement.Location.create(structure, unit);
|
||||
const themeSize = theme.size.size;
|
||||
const center = Vec3();
|
||||
let maxSize = 0;
|
||||
let count = 0;
|
||||
|
||||
for (let i = 0; i < elementCount; i++) {
|
||||
if (ignore?.(elements[i])) continue;
|
||||
|
||||
pos(elements[i], v);
|
||||
builder.add(v[0], v[1], v[2], i);
|
||||
v3add(center, center, v);
|
||||
count += 1;
|
||||
|
||||
l.element = elements[i];
|
||||
const size = themeSize(l);
|
||||
if (size > maxSize) maxSize = size;
|
||||
}
|
||||
|
||||
const oldBoundingSphere = spheres ? Sphere3D.clone(spheres.boundingSphere) : undefined;
|
||||
const s = builder.getSpheres();
|
||||
s.setBoundingSphere(Sphere3D.expand(Sphere3D(), (childUnit ?? unit).boundary.sphere, maxSize * props.sizeFactor + 0.05));
|
||||
if (count === 0) return s;
|
||||
|
||||
// re-use boundingSphere if it has not changed much
|
||||
let boundingSphere: Sphere3D;
|
||||
Vec3.scale(center, center, 1 / count);
|
||||
if (oldBoundingSphere && Vec3.distance(center, oldBoundingSphere.center) / oldBoundingSphere.radius < 1.0) {
|
||||
boundingSphere = oldBoundingSphere;
|
||||
} else {
|
||||
boundingSphere = Sphere3D.expand(Sphere3D(), (childUnit ?? unit).boundary.sphere, maxSize * props.sizeFactor + 0.05);
|
||||
}
|
||||
s.setBoundingSphere(boundingSphere);
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
@@ -16,6 +16,7 @@ import { Lines } from '../../../../mol-geo/geometry/lines/lines';
|
||||
import { LinesBuilder } from '../../../../mol-geo/geometry/lines/lines-builder';
|
||||
import { Cylinders } from '../../../../mol-geo/geometry/cylinders/cylinders';
|
||||
import { CylindersBuilder } from '../../../../mol-geo/geometry/cylinders/cylinders-builder';
|
||||
import { Sphere3D } from '../../../../mol-math/geometry/primitives/sphere3d';
|
||||
|
||||
export const LinkCylinderParams = {
|
||||
linkScale: PD.Numeric(0.45, { min: 0, max: 1, step: 0.01 }),
|
||||
@@ -106,10 +107,10 @@ const v3dot = Vec3.dot;
|
||||
* Each edge is included twice to allow for coloring/picking
|
||||
* the half closer to the first vertex, i.e. vertex a.
|
||||
*/
|
||||
export function createLinkCylinderMesh(ctx: VisualContext, linkBuilder: LinkBuilderProps, props: LinkCylinderProps, mesh?: Mesh) {
|
||||
export function createLinkCylinderMesh(ctx: VisualContext, linkBuilder: LinkBuilderProps, props: LinkCylinderProps, mesh?: Mesh): { mesh: Mesh, boundingSphere?: Sphere3D } {
|
||||
const { linkCount, referencePosition, position, style, radius, ignore, stub } = linkBuilder;
|
||||
|
||||
if (!linkCount) return Mesh.createEmpty(mesh);
|
||||
if (!linkCount) return { mesh: Mesh.createEmpty(mesh) };
|
||||
|
||||
const { linkScale, linkSpacing, radialSegments, linkCap, aromaticScale, aromaticSpacing, aromaticDashCount, dashCount, dashScale, dashCap, stubCap } = props;
|
||||
|
||||
@@ -119,6 +120,10 @@ export function createLinkCylinderMesh(ctx: VisualContext, linkBuilder: LinkBuil
|
||||
const va = Vec3();
|
||||
const vb = Vec3();
|
||||
const vShift = Vec3();
|
||||
|
||||
const center = Vec3();
|
||||
let count = 0;
|
||||
|
||||
const cylinderProps: CylinderProps = {
|
||||
radiusTop: 1,
|
||||
radiusBottom: 1,
|
||||
@@ -133,6 +138,11 @@ export function createLinkCylinderMesh(ctx: VisualContext, linkBuilder: LinkBuil
|
||||
if (ignore && ignore(edgeIndex)) continue;
|
||||
|
||||
position(va, vb, edgeIndex);
|
||||
|
||||
v3add(center, center, va);
|
||||
v3add(center, center, vb);
|
||||
count += 2;
|
||||
|
||||
v3sub(tmpV12, vb, va);
|
||||
const dirFlag = v3dot(tmpV12, up) > 0;
|
||||
|
||||
@@ -234,17 +244,27 @@ export function createLinkCylinderMesh(ctx: VisualContext, linkBuilder: LinkBuil
|
||||
}
|
||||
}
|
||||
|
||||
return MeshBuilder.getMesh(builderState);
|
||||
const oldBoundingSphere = mesh ? Sphere3D.clone(mesh.boundingSphere) : undefined;
|
||||
const m = MeshBuilder.getMesh(builderState);
|
||||
if (count === 0) return { mesh: m };
|
||||
|
||||
// re-use boundingSphere if it has not changed much
|
||||
Vec3.scale(center, center, 1 / count);
|
||||
if (oldBoundingSphere && Vec3.distance(center, oldBoundingSphere.center) / oldBoundingSphere.radius < 1.0) {
|
||||
return { mesh: m, boundingSphere: oldBoundingSphere };
|
||||
} else {
|
||||
return { mesh: m };
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Each edge is included twice to allow for coloring/picking
|
||||
* the half closer to the first vertex, i.e. vertex a.
|
||||
*/
|
||||
export function createLinkCylinderImpostors(ctx: VisualContext, linkBuilder: LinkBuilderProps, props: LinkCylinderProps, cylinders?: Cylinders) {
|
||||
export function createLinkCylinderImpostors(ctx: VisualContext, linkBuilder: LinkBuilderProps, props: LinkCylinderProps, cylinders?: Cylinders): { cylinders: Cylinders, boundingSphere?: Sphere3D } {
|
||||
const { linkCount, referencePosition, position, style, radius, ignore, stub } = linkBuilder;
|
||||
|
||||
if (!linkCount) return Cylinders.createEmpty(cylinders);
|
||||
if (!linkCount) return { cylinders: Cylinders.createEmpty(cylinders) };
|
||||
|
||||
const { linkScale, linkSpacing, linkCap, aromaticScale, aromaticSpacing, aromaticDashCount, dashCount, dashScale, dashCap, stubCap } = props;
|
||||
|
||||
@@ -256,6 +276,9 @@ export function createLinkCylinderImpostors(ctx: VisualContext, linkBuilder: Lin
|
||||
const vm = Vec3();
|
||||
const vShift = Vec3();
|
||||
|
||||
const center = Vec3();
|
||||
let count = 0;
|
||||
|
||||
// automatically adjust length for evenly spaced dashed cylinders
|
||||
const segmentCount = dashCount % 2 === 1 ? dashCount : dashCount + 1;
|
||||
const lengthScale = 0.5 - (0.5 / 2 / segmentCount);
|
||||
@@ -268,6 +291,10 @@ export function createLinkCylinderImpostors(ctx: VisualContext, linkBuilder: Lin
|
||||
|
||||
position(va, vb, edgeIndex);
|
||||
|
||||
v3add(center, center, va);
|
||||
v3add(center, center, vb);
|
||||
count += 2;
|
||||
|
||||
const linkRadius = radius(edgeIndex);
|
||||
const linkStyle = style ? style(edgeIndex) : LinkStyle.Solid;
|
||||
const linkStub = stubCap && (stub ? stub(edgeIndex) : false);
|
||||
@@ -337,17 +364,27 @@ export function createLinkCylinderImpostors(ctx: VisualContext, linkBuilder: Lin
|
||||
}
|
||||
}
|
||||
|
||||
return builder.getCylinders();
|
||||
const oldBoundingSphere = cylinders ? Sphere3D.clone(cylinders.boundingSphere) : undefined;
|
||||
const c = builder.getCylinders();
|
||||
if (count === 0) return { cylinders: c };
|
||||
|
||||
// re-use boundingSphere if it has not changed much
|
||||
Vec3.scale(center, center, 1 / count);
|
||||
if (oldBoundingSphere && Vec3.distance(center, oldBoundingSphere.center) / oldBoundingSphere.radius < 1.0) {
|
||||
return { cylinders: c, boundingSphere: oldBoundingSphere };
|
||||
} else {
|
||||
return { cylinders: c };
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Each edge is included twice to allow for coloring/picking
|
||||
* the half closer to the first vertex, i.e. vertex a.
|
||||
*/
|
||||
export function createLinkLines(ctx: VisualContext, linkBuilder: LinkBuilderProps, props: LinkLineProps, lines?: Lines) {
|
||||
export function createLinkLines(ctx: VisualContext, linkBuilder: LinkBuilderProps, props: LinkLineProps, lines?: Lines): { lines: Lines, boundingSphere?: Sphere3D } {
|
||||
const { linkCount, referencePosition, position, style, ignore } = linkBuilder;
|
||||
|
||||
if (!linkCount) return Lines.createEmpty(lines);
|
||||
if (!linkCount) return { lines: Lines.createEmpty(lines) };
|
||||
|
||||
const { linkScale, linkSpacing, aromaticDashCount, dashCount } = props;
|
||||
|
||||
@@ -359,6 +396,9 @@ export function createLinkLines(ctx: VisualContext, linkBuilder: LinkBuilderProp
|
||||
const vm = Vec3();
|
||||
const vShift = Vec3();
|
||||
|
||||
const center = Vec3();
|
||||
let count = 0;
|
||||
|
||||
// automatically adjust length for evenly spaced dashed lines
|
||||
const segmentCount = dashCount % 2 === 1 ? dashCount : dashCount + 1;
|
||||
const lengthScale = 0.5 - (0.5 / 2 / segmentCount);
|
||||
@@ -373,6 +413,10 @@ export function createLinkLines(ctx: VisualContext, linkBuilder: LinkBuilderProp
|
||||
|
||||
position(va, vb, edgeIndex);
|
||||
|
||||
v3add(center, center, va);
|
||||
v3add(center, center, vb);
|
||||
count += 2;
|
||||
|
||||
const linkStyle = style ? style(edgeIndex) : LinkStyle.Solid;
|
||||
|
||||
if (linkStyle === LinkStyle.Solid) {
|
||||
@@ -435,5 +479,15 @@ export function createLinkLines(ctx: VisualContext, linkBuilder: LinkBuilderProp
|
||||
}
|
||||
}
|
||||
|
||||
return builder.getLines();
|
||||
const oldBoundingSphere = lines ? Sphere3D.clone(lines.boundingSphere) : undefined;
|
||||
const l = builder.getLines();
|
||||
if (count === 0) return { lines: l };
|
||||
|
||||
// re-use boundingSphere if it has not changed much
|
||||
Vec3.scale(center, center, 1 / count);
|
||||
if (oldBoundingSphere && Vec3.distance(center, oldBoundingSphere.center) / oldBoundingSphere.radius < 1.0) {
|
||||
return { lines: l, boundingSphere: oldBoundingSphere };
|
||||
} else {
|
||||
return { lines: l };
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user