|
@@ -1,8 +1,9 @@
|
|
|
/**
|
|
|
- * Copyright (c) 2018-2021 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
|
|
+ * Copyright (c) 2018-2023 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
|
|
*
|
|
|
* @author Alexander Rose <alexander.rose@weirdbyte.de>
|
|
|
* @author Zhenyu Zhang <jump2cn@gmail.com>
|
|
|
+ * @author Gianluca Tomasello <giagitom@gmail.com>
|
|
|
*/
|
|
|
|
|
|
import { Vec3 } from '../../../../mol-math/linear-algebra';
|
|
@@ -25,8 +26,8 @@ export const LinkCylinderParams = {
|
|
|
linkCap: PD.Boolean(false),
|
|
|
aromaticScale: PD.Numeric(0.3, { min: 0, max: 1, step: 0.01 }),
|
|
|
aromaticSpacing: PD.Numeric(1.5, { min: 0, max: 3, step: 0.01 }),
|
|
|
- aromaticDashCount: PD.Numeric(2, { min: 2, max: 6, step: 2 }),
|
|
|
- dashCount: PD.Numeric(4, { min: 0, max: 10, step: 2 }),
|
|
|
+ aromaticDashCount: PD.Numeric(2, { min: 1, max: 6, step: 1 }),
|
|
|
+ dashCount: PD.Numeric(4, { min: 0, max: 10, step: 1 }),
|
|
|
dashScale: PD.Numeric(0.8, { min: 0, max: 2, step: 0.1 }),
|
|
|
dashCap: PD.Boolean(true),
|
|
|
stubCap: PD.Boolean(true),
|
|
@@ -38,8 +39,8 @@ export type LinkCylinderProps = typeof DefaultLinkCylinderProps
|
|
|
export const LinkLineParams = {
|
|
|
linkScale: PD.Numeric(0.5, { min: 0, max: 1, step: 0.1 }),
|
|
|
linkSpacing: PD.Numeric(0.1, { min: 0, max: 2, step: 0.01 }),
|
|
|
- aromaticDashCount: PD.Numeric(2, { min: 2, max: 6, step: 2 }),
|
|
|
- dashCount: PD.Numeric(4, { min: 0, max: 10, step: 2 }),
|
|
|
+ aromaticDashCount: PD.Numeric(2, { min: 1, max: 6, step: 1 }),
|
|
|
+ dashCount: PD.Numeric(4, { min: 0, max: 10, step: 1 }),
|
|
|
};
|
|
|
export const DefaultLinkLineProps = PD.getDefaultValues(LinkLineParams);
|
|
|
export type LinkLineProps = typeof DefaultLinkLineProps
|
|
@@ -133,8 +134,6 @@ export function createLinkCylinderMesh(ctx: VisualContext, linkBuilder: LinkBuil
|
|
|
bottomCap: linkCap
|
|
|
};
|
|
|
|
|
|
- const segmentCount = dashCount + 1;
|
|
|
-
|
|
|
for (let edgeIndex = 0, _eI = linkCount; edgeIndex < _eI; ++edgeIndex) {
|
|
|
if (ignore && ignore(edgeIndex)) continue;
|
|
|
|
|
@@ -153,8 +152,6 @@ export function createLinkCylinderMesh(ctx: VisualContext, linkBuilder: LinkBuil
|
|
|
const [topCap, bottomCap] = dirFlag ? [linkStub, linkCap] : [linkCap, linkStub];
|
|
|
builderState.currentGroup = edgeIndex;
|
|
|
|
|
|
- const aromaticSegmentCount = aromaticDashCount + 1;
|
|
|
-
|
|
|
if (linkStyle === LinkStyle.Solid) {
|
|
|
cylinderProps.radiusTop = cylinderProps.radiusBottom = linkRadius;
|
|
|
cylinderProps.topCap = topCap;
|
|
@@ -164,12 +161,7 @@ export function createLinkCylinderMesh(ctx: VisualContext, linkBuilder: LinkBuil
|
|
|
} else if (linkStyle === LinkStyle.Dashed) {
|
|
|
cylinderProps.radiusTop = cylinderProps.radiusBottom = linkRadius * dashScale;
|
|
|
cylinderProps.topCap = cylinderProps.bottomCap = dashCap;
|
|
|
-
|
|
|
- if (segmentCount > 1) {
|
|
|
- addFixedCountDashedCylinder(builderState, va, vb, 0.5, segmentCount, cylinderProps);
|
|
|
- } else {
|
|
|
- addCylinder(builderState, va, vb, 0.5, cylinderProps);
|
|
|
- }
|
|
|
+ addFixedCountDashedCylinder(builderState, va, vb, 0.5, dashCount, linkStub, cylinderProps);
|
|
|
} else if (linkStyle === LinkStyle.Double || linkStyle === LinkStyle.OffsetDouble || linkStyle === LinkStyle.Triple || linkStyle === LinkStyle.OffsetTriple || linkStyle === LinkStyle.Aromatic || linkStyle === LinkStyle.MirroredAromatic) {
|
|
|
const order = (linkStyle === LinkStyle.Double || linkStyle === LinkStyle.OffsetDouble) ? 2 :
|
|
|
(linkStyle === LinkStyle.Triple || linkStyle === LinkStyle.OffsetTriple) ? 3 : 1.5;
|
|
@@ -196,13 +188,13 @@ export function createLinkCylinderMesh(ctx: VisualContext, linkBuilder: LinkBuil
|
|
|
v3setMagnitude(vShift, vShift, aromaticOffset);
|
|
|
v3sub(va, va, vShift);
|
|
|
v3sub(vb, vb, vShift);
|
|
|
- addFixedCountDashedCylinder(builderState, va, vb, 0.5, aromaticSegmentCount, cylinderProps);
|
|
|
+ addFixedCountDashedCylinder(builderState, va, vb, 0.5, aromaticDashCount, linkStub, cylinderProps);
|
|
|
|
|
|
if (linkStyle === LinkStyle.MirroredAromatic) {
|
|
|
v3setMagnitude(vShift, vShift, aromaticOffset * 2);
|
|
|
v3add(va, va, vShift);
|
|
|
v3add(vb, vb, vShift);
|
|
|
- addFixedCountDashedCylinder(builderState, va, vb, 0.5, aromaticSegmentCount, cylinderProps);
|
|
|
+ addFixedCountDashedCylinder(builderState, va, vb, 0.5, aromaticDashCount, linkStub, cylinderProps);
|
|
|
}
|
|
|
} else if (linkStyle === LinkStyle.OffsetDouble || linkStyle === LinkStyle.OffsetTriple) {
|
|
|
const multipleOffset = linkRadius + multiRadius + linkScale * linkRadius * linkSpacing;
|
|
@@ -284,13 +276,6 @@ export function createLinkCylinderImpostors(ctx: VisualContext, linkBuilder: Lin
|
|
|
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);
|
|
|
-
|
|
|
- const aromaticSegmentCount = aromaticDashCount + 1;
|
|
|
- const aromaticLengthScale = 0.5 - (0.5 / 2 / aromaticSegmentCount);
|
|
|
-
|
|
|
for (let edgeIndex = 0, _eI = linkCount; edgeIndex < _eI; ++edgeIndex) {
|
|
|
if (ignore && ignore(edgeIndex)) continue;
|
|
|
|
|
@@ -308,14 +293,8 @@ export function createLinkCylinderImpostors(ctx: VisualContext, linkBuilder: Lin
|
|
|
v3scale(vm, v3add(vm, va, vb), 0.5);
|
|
|
builder.add(va[0], va[1], va[2], vm[0], vm[1], vm[2], 1, linkCap, linkStub, edgeIndex);
|
|
|
} else if (linkStyle === LinkStyle.Dashed) {
|
|
|
- if (segmentCount > 1) {
|
|
|
- v3scale(tmpV12, v3sub(tmpV12, vb, va), lengthScale);
|
|
|
- v3sub(vb, vb, tmpV12);
|
|
|
- builder.addFixedCountDashes(va, vb, segmentCount, dashScale, dashCap, dashCap, edgeIndex);
|
|
|
- } else {
|
|
|
- v3scale(vm, v3add(vm, va, vb), 0.5);
|
|
|
- builder.add(va[0], va[1], va[2], vm[0], vm[1], vm[2], dashScale, dashCap, dashCap, edgeIndex);
|
|
|
- }
|
|
|
+ v3scale(vm, v3add(vm, va, vb), 0.5);
|
|
|
+ builder.addFixedCountDashes(va, vm, dashCount, dashScale, dashCap, dashCap, linkStub, edgeIndex);
|
|
|
} else if (linkStyle === LinkStyle.Double || linkStyle === LinkStyle.OffsetDouble || linkStyle === LinkStyle.Triple || linkStyle === LinkStyle.OffsetTriple || linkStyle === LinkStyle.Aromatic || linkStyle === LinkStyle.MirroredAromatic) {
|
|
|
const order = (linkStyle === LinkStyle.Double || linkStyle === LinkStyle.OffsetDouble) ? 2 :
|
|
|
(linkStyle === LinkStyle.Triple || linkStyle === LinkStyle.OffsetTriple) ? 3 : 1.5;
|
|
@@ -330,22 +309,19 @@ export function createLinkCylinderImpostors(ctx: VisualContext, linkBuilder: Lin
|
|
|
|
|
|
const aromaticOffset = linkRadius + aromaticScale * linkRadius + aromaticScale * linkRadius * aromaticSpacing;
|
|
|
|
|
|
- v3scale(tmpV12, v3sub(tmpV12, vb, va), aromaticLengthScale);
|
|
|
- v3sub(vb, vb, tmpV12);
|
|
|
-
|
|
|
v3setMagnitude(tmpV12, v3sub(tmpV12, vb, va), linkRadius * 0.5);
|
|
|
v3add(va, va, tmpV12);
|
|
|
|
|
|
v3setMagnitude(vShift, vShift, aromaticOffset);
|
|
|
v3sub(va, va, vShift);
|
|
|
- v3sub(vb, vb, vShift);
|
|
|
- builder.addFixedCountDashes(va, vb, aromaticSegmentCount, aromaticScale, dashCap, dashCap, edgeIndex);
|
|
|
+ v3sub(vm, vm, vShift);
|
|
|
+ builder.addFixedCountDashes(va, vm, aromaticDashCount, aromaticScale, dashCap, dashCap, linkStub, edgeIndex);
|
|
|
|
|
|
if (linkStyle === LinkStyle.MirroredAromatic) {
|
|
|
v3setMagnitude(vShift, vShift, aromaticOffset * 2);
|
|
|
v3add(va, va, vShift);
|
|
|
- v3add(vb, vb, vShift);
|
|
|
- builder.addFixedCountDashes(va, vb, aromaticSegmentCount, aromaticScale, dashCap, dashCap, edgeIndex);
|
|
|
+ v3add(vm, vm, vShift);
|
|
|
+ builder.addFixedCountDashes(va, vm, aromaticDashCount, aromaticScale, dashCap, dashCap, linkStub, edgeIndex);
|
|
|
}
|
|
|
} else if (linkStyle === LinkStyle.OffsetDouble || linkStyle === LinkStyle.OffsetTriple) {
|
|
|
const multipleOffset = linkRadius + multiScale * linkRadius + linkScale * linkRadius * linkSpacing;
|
|
@@ -353,7 +329,7 @@ export function createLinkCylinderImpostors(ctx: VisualContext, linkBuilder: Lin
|
|
|
|
|
|
builder.add(va[0], va[1], va[2], vm[0], vm[1], vm[2], 1, linkCap, linkStub, edgeIndex);
|
|
|
|
|
|
- v3setMagnitude(tmpV12, v3sub(tmpV12, va, vb), linkRadius / 1.5);
|
|
|
+ v3setMagnitude(tmpV12, v3sub(tmpV12, va, vm), linkRadius / 1.5);
|
|
|
v3sub(va, va, tmpV12);
|
|
|
|
|
|
if (order === 3) builder.add(va[0] + vShift[0], va[1] + vShift[1], va[2] + vShift[2], vm[0] + vShift[0], vm[1] + vShift[1], vm[2] + vShift[2], multiScale, linkCap, linkStub, edgeIndex);
|
|
@@ -366,11 +342,11 @@ export function createLinkCylinderImpostors(ctx: VisualContext, linkBuilder: Lin
|
|
|
builder.add(va[0] - vShift[0], va[1] - vShift[1], va[2] - vShift[2], vm[0] - vShift[0], vm[1] - vShift[1], vm[2] - vShift[2], multiScale, linkCap, linkStub, edgeIndex);
|
|
|
}
|
|
|
} else if (linkStyle === LinkStyle.Disk) {
|
|
|
- v3scale(tmpV12, v3sub(tmpV12, vb, va), 0.475);
|
|
|
+ v3scale(tmpV12, v3sub(tmpV12, vm, va), 0.475);
|
|
|
v3add(va, va, tmpV12);
|
|
|
- v3sub(vb, vb, tmpV12);
|
|
|
+ v3sub(vm, vm, tmpV12);
|
|
|
|
|
|
- builder.add(va[0], va[1], va[2], vb[0], vb[1], vb[2], 1, linkCap, linkStub, edgeIndex);
|
|
|
+ builder.add(va[0], va[1], va[2], vm[0], vm[1], vm[2], 1, linkCap, linkStub, edgeIndex);
|
|
|
}
|
|
|
}
|
|
|
|
|
@@ -409,12 +385,6 @@ export function createLinkLines(ctx: VisualContext, linkBuilder: LinkBuilderProp
|
|
|
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);
|
|
|
-
|
|
|
- const aromaticSegmentCount = aromaticDashCount + 1;
|
|
|
- const aromaticLengthScale = 0.5 - (0.5 / 2 / aromaticSegmentCount);
|
|
|
const aromaticOffsetFactor = 4.5;
|
|
|
const multipleOffsetFactor = 3;
|
|
|
|
|
@@ -433,14 +403,8 @@ export function createLinkLines(ctx: VisualContext, linkBuilder: LinkBuilderProp
|
|
|
v3scale(vm, v3add(vm, va, vb), 0.5);
|
|
|
builder.add(va[0], va[1], va[2], vm[0], vm[1], vm[2], edgeIndex);
|
|
|
} else if (linkStyle === LinkStyle.Dashed) {
|
|
|
- if (segmentCount > 1) {
|
|
|
- v3scale(tmpV12, v3sub(tmpV12, vb, va), lengthScale);
|
|
|
- v3sub(vb, vb, tmpV12);
|
|
|
- builder.addFixedCountDashes(va, vb, segmentCount, edgeIndex);
|
|
|
- } else {
|
|
|
- v3scale(vm, v3add(vm, va, vb), 0.5);
|
|
|
- builder.add(va[0], va[1], va[2], vm[0], vm[1], vm[2], edgeIndex);
|
|
|
- }
|
|
|
+ v3scale(vm, v3add(vm, va, vb), 0.5);
|
|
|
+ builder.addFixedCountDashes(va, vm, dashCount, edgeIndex);
|
|
|
} else if (linkStyle === LinkStyle.Double || linkStyle === LinkStyle.OffsetDouble || linkStyle === LinkStyle.Triple || linkStyle === LinkStyle.OffsetTriple || linkStyle === LinkStyle.Aromatic || linkStyle === LinkStyle.MirroredAromatic) {
|
|
|
const order = linkStyle === LinkStyle.Double || linkStyle === LinkStyle.OffsetDouble ? 2 :
|
|
|
linkStyle === LinkStyle.Triple || linkStyle === LinkStyle.OffsetTriple ? 3 : 1.5;
|
|
@@ -453,26 +417,28 @@ export function createLinkLines(ctx: VisualContext, linkBuilder: LinkBuilderProp
|
|
|
if (linkStyle === LinkStyle.Aromatic || linkStyle === LinkStyle.MirroredAromatic) {
|
|
|
builder.add(va[0], va[1], va[2], vm[0], vm[1], vm[2], edgeIndex);
|
|
|
|
|
|
- v3scale(tmpV12, v3sub(tmpV12, vb, va), aromaticLengthScale);
|
|
|
- v3sub(vb, vb, tmpV12);
|
|
|
+ const aromaticOffset = absOffset * aromaticOffsetFactor;
|
|
|
|
|
|
- v3setMagnitude(vShift, vShift, absOffset * aromaticOffsetFactor);
|
|
|
+ v3setMagnitude(tmpV12, v3sub(tmpV12, vb, va), aromaticOffset * 0.5);
|
|
|
+ v3add(va, va, tmpV12);
|
|
|
+
|
|
|
+ v3setMagnitude(vShift, vShift, aromaticOffset);
|
|
|
v3sub(va, va, vShift);
|
|
|
- v3sub(vb, vb, vShift);
|
|
|
- builder.addFixedCountDashes(va, vb, aromaticSegmentCount, edgeIndex);
|
|
|
+ v3sub(vm, vm, vShift);
|
|
|
+ builder.addFixedCountDashes(va, vm, aromaticDashCount, edgeIndex);
|
|
|
|
|
|
if (linkStyle === LinkStyle.MirroredAromatic) {
|
|
|
- v3setMagnitude(vShift, vShift, absOffset * aromaticOffsetFactor * 2);
|
|
|
+ v3setMagnitude(vShift, vShift, aromaticOffset * 2);
|
|
|
v3add(va, va, vShift);
|
|
|
- v3add(vb, vb, vShift);
|
|
|
- builder.addFixedCountDashes(va, vb, aromaticSegmentCount, edgeIndex);
|
|
|
+ v3add(vm, vm, vShift);
|
|
|
+ builder.addFixedCountDashes(va, vm, aromaticDashCount, edgeIndex);
|
|
|
}
|
|
|
} else if (linkStyle === LinkStyle.OffsetDouble || linkStyle === LinkStyle.OffsetTriple) {
|
|
|
v3setMagnitude(vShift, vShift, absOffset * multipleOffsetFactor);
|
|
|
|
|
|
builder.add(va[0], va[1], va[2], vm[0], vm[1], vm[2], edgeIndex);
|
|
|
|
|
|
- v3scale(tmpV12, v3sub(tmpV12, va, vb), linkSpacing * linkScale);
|
|
|
+ v3scale(tmpV12, v3sub(tmpV12, va, vm), linkSpacing * linkScale);
|
|
|
v3sub(va, va, tmpV12);
|
|
|
|
|
|
if (order === 3) builder.add(va[0] + vShift[0], va[1] + vShift[1], va[2] + vShift[2], vm[0] + vShift[0], vm[1] + vShift[1], vm[2] + vShift[2], edgeIndex);
|
|
@@ -485,12 +451,12 @@ export function createLinkLines(ctx: VisualContext, linkBuilder: LinkBuilderProp
|
|
|
builder.add(va[0] - vShift[0], va[1] - vShift[1], va[2] - vShift[2], vm[0] - vShift[0], vm[1] - vShift[1], vm[2] - vShift[2], edgeIndex);
|
|
|
}
|
|
|
} else if (linkStyle === LinkStyle.Disk) {
|
|
|
- v3scale(tmpV12, v3sub(tmpV12, vb, va), 0.475);
|
|
|
+ v3scale(tmpV12, v3sub(tmpV12, vm, va), 0.475);
|
|
|
v3add(va, va, tmpV12);
|
|
|
- v3sub(vb, vb, tmpV12);
|
|
|
+ v3sub(vm, vm, tmpV12);
|
|
|
|
|
|
// 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);
|
|
|
+ builder.add(va[0], va[1], va[2], vm[0], vm[1], vm[2], edgeIndex);
|
|
|
}
|
|
|
}
|
|
|
|
|
@@ -505,4 +471,4 @@ export function createLinkLines(ctx: VisualContext, linkBuilder: LinkBuilderProp
|
|
|
} else {
|
|
|
return { lines: l };
|
|
|
}
|
|
|
-}
|
|
|
+}
|