diff --git a/CHANGELOG.md b/CHANGELOG.md index 993d1e72f329a1b38f2d2c14af064e2471012967..28d051aa7b6b5b422fd4586fd8fa4714774bca71 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,8 @@ Note that since we don't clearly distinguish between a public and private interf ## [Unreleased] +- Fix color smoothing of elongated structures (by fixing ``Sphere.expand`` for spheres with highly directional extrema) + ## [v3.0.1] - 2022-01-27 - Fix marking pass not working with ``transparentBackground`` diff --git a/src/mol-math/geometry/primitives/sphere3d.ts b/src/mol-math/geometry/primitives/sphere3d.ts index 1f428762747b458d8c3314cd0fad1cbb6d62d01c..8356dbf0d5ef8aca71d12ea3cf29dc10541234c8 100644 --- a/src/mol-math/geometry/primitives/sphere3d.ts +++ b/src/mol-math/geometry/primitives/sphere3d.ts @@ -1,5 +1,5 @@ /** - * Copyright (c) 2018-2020 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 David Sehnal <david.sehnal@gmail.com> * @author Alexander Rose <alexander.rose@weirdbyte.de> @@ -11,6 +11,7 @@ import { OrderedSet } from '../../../mol-data/int'; import { NumberArray, PickRequired } from '../../../mol-util/type-helpers'; import { Box3D } from './box3d'; import { Axes3D } from './axes3d'; +import { PrincipalAxes } from '../../linear-algebra/matrix/principal-axes'; interface Sphere3D { center: Vec3, @@ -202,11 +203,28 @@ namespace Sphere3D { return out; } if (hasExtrema(sphere)) { + const positions = new Float32Array(sphere.extrema.length * 3); + for (let i = 0; i < sphere.extrema.length; i++) { + Vec3.toArray(sphere.extrema[i], positions, i * 3); + } + + const axes = PrincipalAxes.calculateMomentsAxes(positions); + Axes3D.scale(axes, Axes3D.normalize(axes, axes), delta); + setExtrema(out, sphere.extrema.map(e => { Vec3.sub(tmpDir, e, sphere.center); - const dist = Vec3.distance(sphere.center, e); - Vec3.normalize(tmpDir, tmpDir); - return Vec3.scaleAndAdd(Vec3(), sphere.center, tmpDir, dist + delta); + const out = Vec3.clone(e); + + const sA = Vec3.dot(tmpDir, axes.dirA) < 0 ? -1 : 1; + Vec3.scaleAndAdd(out, out, axes.dirA, sA); + + const sB = Vec3.dot(tmpDir, axes.dirB) < 0 ? -1 : 1; + Vec3.scaleAndAdd(out, out, axes.dirB, sB); + + const sC = Vec3.dot(tmpDir, axes.dirC) < 0 ? -1 : 1; + Vec3.scaleAndAdd(out, out, axes.dirC, sC); + + return out; })); } return out; diff --git a/src/mol-repr/structure/visual/molecular-surface-mesh.ts b/src/mol-repr/structure/visual/molecular-surface-mesh.ts index 08f3296863f55b1d28c898b76995f29419f7736a..306bccb0c5e1a0ccdce43218e42ed07516e34aed 100644 --- a/src/mol-repr/structure/visual/molecular-surface-mesh.ts +++ b/src/mol-repr/structure/visual/molecular-surface-mesh.ts @@ -1,5 +1,5 @@ /** - * Copyright (c) 2019-2021 mol* contributors, licensed under MIT, See LICENSE file for more info. + * Copyright (c) 2019-2022 mol* contributors, licensed under MIT, See LICENSE file for more info. * * @author Alexander Rose <alexander.rose@weirdbyte.de> */ @@ -57,7 +57,7 @@ async function createMolecularSurfaceMesh(ctx: VisualContext, unit: Unit, struct Mesh.transform(surface, transform); if (ctx.webgl && !ctx.webgl.isWebGL2) Mesh.uniformTriangleGroup(surface); - const sphere = Sphere3D.expand(Sphere3D(), unit.boundary.sphere, props.probeRadius + getUnitExtraRadius(unit)); + const sphere = Sphere3D.expand(Sphere3D(), unit.boundary.sphere, getUnitExtraRadius(unit)); surface.setBoundingSphere(sphere); (surface.meta as MolecularSurfaceMeta).resolution = resolution;