|
@@ -21,6 +21,9 @@ export const LinkCylinderParams = {
|
|
|
linkScale: PD.Numeric(0.45, { min: 0, max: 1, step: 0.01 }),
|
|
|
linkSpacing: PD.Numeric(1, { min: 0, max: 2, step: 0.01 }),
|
|
|
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: 2, max: 10, step: 2 }),
|
|
|
dashScale: PD.Numeric(0.8, { min: 0, max: 2, step: 0.1 }),
|
|
|
dashCap: PD.Boolean(true),
|
|
@@ -33,6 +36,7 @@ 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: 2, max: 10, step: 2 }),
|
|
|
};
|
|
|
export const DefaultLinkLineProps = PD.getDefaultValues(LinkLineParams);
|
|
@@ -107,7 +111,7 @@ export function createLinkCylinderMesh(ctx: VisualContext, linkBuilder: LinkBuil
|
|
|
|
|
|
if (!linkCount) return Mesh.createEmpty(mesh);
|
|
|
|
|
|
- const { linkScale, linkSpacing, radialSegments, linkCap, dashCount, dashScale, dashCap, stubCap } = props;
|
|
|
+ const { linkScale, linkSpacing, radialSegments, linkCap, aromaticScale, aromaticSpacing, aromaticDashCount, dashCount, dashScale, dashCap, stubCap } = props;
|
|
|
|
|
|
const vertexCountEstimate = radialSegments * 2 * linkCount * 2;
|
|
|
const builderState = MeshBuilder.createState(vertexCountEstimate, vertexCountEstimate / 4, mesh);
|
|
@@ -138,8 +142,7 @@ export function createLinkCylinderMesh(ctx: VisualContext, linkBuilder: LinkBuil
|
|
|
const [topCap, bottomCap] = dirFlag ? [linkStub, linkCap] : [linkCap, linkStub];
|
|
|
builderState.currentGroup = edgeIndex;
|
|
|
|
|
|
- const aromaticOffsetFactor = 5.5;
|
|
|
- const multipleOffsetFactor = 4;
|
|
|
+ const aromaticSegmentCount = aromaticDashCount + 1;
|
|
|
|
|
|
if (linkStyle === LinkStyle.Solid) {
|
|
|
cylinderProps.radiusTop = cylinderProps.radiusBottom = linkRadius;
|
|
@@ -153,8 +156,8 @@ export function createLinkCylinderMesh(ctx: VisualContext, linkBuilder: LinkBuil
|
|
|
|
|
|
addFixedCountDashedCylinder(builderState, va, vb, 0.5, segmentCount, 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;
|
|
|
+ const order = (linkStyle === LinkStyle.Double || linkStyle === LinkStyle.OffsetDouble) ? 2 :
|
|
|
+ (linkStyle === LinkStyle.Triple || linkStyle === LinkStyle.OffsetTriple) ? 3 : 1.5;
|
|
|
const multiRadius = linkRadius * (linkScale / (0.5 * order));
|
|
|
const absOffset = (linkRadius - multiRadius) * linkSpacing;
|
|
|
|
|
@@ -167,21 +170,28 @@ export function createLinkCylinderMesh(ctx: VisualContext, linkBuilder: LinkBuil
|
|
|
cylinderProps.radiusTop = cylinderProps.radiusBottom = linkRadius;
|
|
|
addCylinder(builderState, va, vb, 0.5, cylinderProps);
|
|
|
|
|
|
- cylinderProps.radiusTop = cylinderProps.radiusBottom = linkRadius * linkScale;
|
|
|
+ const aromaticOffset = linkRadius + aromaticScale * linkRadius + aromaticScale * linkRadius * aromaticSpacing;
|
|
|
+
|
|
|
+ v3setMagnitude(tmpV12, v3sub(tmpV12, vb, va), linkRadius * 0.5);
|
|
|
+ v3add(va, va, tmpV12);
|
|
|
+ v3sub(vb, vb, tmpV12);
|
|
|
+
|
|
|
+ cylinderProps.radiusTop = cylinderProps.radiusBottom = linkRadius * aromaticScale;
|
|
|
cylinderProps.topCap = cylinderProps.bottomCap = dashCap;
|
|
|
- v3setMagnitude(vShift, vShift, absOffset * aromaticOffsetFactor);
|
|
|
+ v3setMagnitude(vShift, vShift, aromaticOffset);
|
|
|
v3sub(va, va, vShift);
|
|
|
v3sub(vb, vb, vShift);
|
|
|
- addFixedCountDashedCylinder(builderState, va, vb, 0.5, 3, cylinderProps);
|
|
|
+ addFixedCountDashedCylinder(builderState, va, vb, 0.5, aromaticSegmentCount, cylinderProps);
|
|
|
|
|
|
if (linkStyle === LinkStyle.MirroredAromatic) {
|
|
|
- v3setMagnitude(vShift, vShift, absOffset * aromaticOffsetFactor * 2);
|
|
|
+ v3setMagnitude(vShift, vShift, aromaticOffset * 2);
|
|
|
v3add(va, va, vShift);
|
|
|
v3add(vb, vb, vShift);
|
|
|
- addFixedCountDashedCylinder(builderState, va, vb, 0.5, 3, cylinderProps);
|
|
|
+ addFixedCountDashedCylinder(builderState, va, vb, 0.5, aromaticSegmentCount, cylinderProps);
|
|
|
}
|
|
|
} else if (linkStyle === LinkStyle.OffsetDouble || linkStyle === LinkStyle.OffsetTriple) {
|
|
|
- v3setMagnitude(vShift, vShift, absOffset);
|
|
|
+ const multipleOffset = linkRadius + multiRadius + linkScale * linkRadius * linkSpacing;
|
|
|
+ v3setMagnitude(vShift, vShift, multipleOffset);
|
|
|
|
|
|
cylinderProps.radiusTop = cylinderProps.radiusBottom = linkRadius;
|
|
|
addCylinder(builderState, va, vb, 0.5, cylinderProps);
|
|
@@ -193,13 +203,13 @@ export function createLinkCylinderMesh(ctx: VisualContext, linkBuilder: LinkBuil
|
|
|
cylinderProps.radiusTop = cylinderProps.radiusBottom = multiRadius;
|
|
|
cylinderProps.topCap = dirFlag ? linkStub : dashCap;
|
|
|
cylinderProps.bottomCap = dirFlag ? dashCap : linkStub;
|
|
|
- v3setMagnitude(vShift, vShift, absOffset * multipleOffsetFactor);
|
|
|
+ v3setMagnitude(vShift, vShift, multipleOffset);
|
|
|
v3sub(va, va, vShift);
|
|
|
v3sub(vb, vb, vShift);
|
|
|
addCylinder(builderState, va, vb, 0.5, cylinderProps);
|
|
|
|
|
|
if (order === 3) {
|
|
|
- v3setMagnitude(vShift, vShift, absOffset * multipleOffsetFactor * 2);
|
|
|
+ v3setMagnitude(vShift, vShift, multipleOffset * 2);
|
|
|
v3add(va, va, vShift);
|
|
|
v3add(vb, vb, vShift);
|
|
|
addCylinder(builderState, va, vb, 0.5, cylinderProps);
|
|
@@ -236,7 +246,7 @@ export function createLinkCylinderImpostors(ctx: VisualContext, linkBuilder: Lin
|
|
|
|
|
|
if (!linkCount) return Cylinders.createEmpty(cylinders);
|
|
|
|
|
|
- const { linkScale, linkSpacing, linkCap, dashCount, dashScale, dashCap, stubCap } = props;
|
|
|
+ const { linkScale, linkSpacing, linkCap, aromaticScale, aromaticSpacing, aromaticDashCount, dashCount, dashScale, dashCap, stubCap } = props;
|
|
|
|
|
|
const cylindersCountEstimate = linkCount * 2;
|
|
|
const builder = CylindersBuilder.create(cylindersCountEstimate, cylindersCountEstimate / 4, cylinders);
|
|
@@ -250,10 +260,8 @@ export function createLinkCylinderImpostors(ctx: VisualContext, linkBuilder: Lin
|
|
|
const segmentCount = dashCount % 2 === 1 ? dashCount : dashCount + 1;
|
|
|
const lengthScale = 0.5 - (0.5 / 2 / segmentCount);
|
|
|
|
|
|
- const aromaticSegmentCount = 3;
|
|
|
+ const aromaticSegmentCount = aromaticDashCount + 1;
|
|
|
const aromaticLengthScale = 0.5 - (0.5 / 2 / aromaticSegmentCount);
|
|
|
- const aromaticOffsetFactor = 5.5;
|
|
|
- const multipleOffsetFactor = 4;
|
|
|
|
|
|
for (let edgeIndex = 0, _eI = linkCount; edgeIndex < _eI; ++edgeIndex) {
|
|
|
if (ignore && ignore(edgeIndex)) continue;
|
|
@@ -272,8 +280,8 @@ export function createLinkCylinderImpostors(ctx: VisualContext, linkBuilder: Lin
|
|
|
v3sub(vb, vb, tmpV12);
|
|
|
builder.addFixedCountDashes(va, vb, segmentCount, dashScale, dashCap, dashCap, 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;
|
|
|
+ const order = (linkStyle === LinkStyle.Double || linkStyle === LinkStyle.OffsetDouble) ? 2 :
|
|
|
+ (linkStyle === LinkStyle.Triple || linkStyle === LinkStyle.OffsetTriple) ? 3 : 1.5;
|
|
|
const multiScale = linkScale / (0.5 * order);
|
|
|
const absOffset = (linkRadius - multiScale * linkRadius) * linkSpacing;
|
|
|
|
|
@@ -283,26 +291,32 @@ export function createLinkCylinderImpostors(ctx: VisualContext, linkBuilder: Lin
|
|
|
if (linkStyle === LinkStyle.Aromatic || linkStyle === LinkStyle.MirroredAromatic) {
|
|
|
builder.add(va[0], va[1], va[2], vm[0], vm[1], vm[2], 1, linkCap, linkStub, edgeIndex);
|
|
|
|
|
|
+ const aromaticOffset = linkRadius + aromaticScale * linkRadius + aromaticScale * linkRadius * aromaticSpacing;
|
|
|
+
|
|
|
v3scale(tmpV12, v3sub(tmpV12, vb, va), aromaticLengthScale);
|
|
|
v3sub(vb, vb, tmpV12);
|
|
|
|
|
|
- v3setMagnitude(vShift, vShift, absOffset * aromaticOffsetFactor);
|
|
|
+ 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, linkScale, dashCap, dashCap, edgeIndex);
|
|
|
+ builder.addFixedCountDashes(va, vb, aromaticSegmentCount, aromaticScale, dashCap, dashCap, 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, linkScale, dashCap, dashCap, edgeIndex);
|
|
|
+ builder.addFixedCountDashes(va, vb, aromaticSegmentCount, aromaticScale, dashCap, dashCap, edgeIndex);
|
|
|
}
|
|
|
} else if (linkStyle === LinkStyle.OffsetDouble || linkStyle === LinkStyle.OffsetTriple) {
|
|
|
- v3setMagnitude(vShift, vShift, absOffset * multipleOffsetFactor);
|
|
|
+ const multipleOffset = linkRadius + multiScale * linkRadius + linkScale * linkRadius * linkSpacing;
|
|
|
+ v3setMagnitude(vShift, vShift, multipleOffset);
|
|
|
|
|
|
builder.add(va[0], va[1], va[2], vm[0], vm[1], vm[2], 1, linkCap, linkStub, edgeIndex);
|
|
|
|
|
|
- v3scale(tmpV12, v3sub(tmpV12, va, vb), linkSpacing * linkScale * 0.2);
|
|
|
+ v3setMagnitude(tmpV12, v3sub(tmpV12, va, vb), 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);
|
|
@@ -335,7 +349,7 @@ export function createLinkLines(ctx: VisualContext, linkBuilder: LinkBuilderProp
|
|
|
|
|
|
if (!linkCount) return Lines.createEmpty(lines);
|
|
|
|
|
|
- const { linkScale, linkSpacing, dashCount } = props;
|
|
|
+ const { linkScale, linkSpacing, aromaticDashCount, dashCount } = props;
|
|
|
|
|
|
const linesCountEstimate = linkCount * 2;
|
|
|
const builder = LinesBuilder.create(linesCountEstimate, linesCountEstimate / 4, lines);
|
|
@@ -349,7 +363,7 @@ export function createLinkLines(ctx: VisualContext, linkBuilder: LinkBuilderProp
|
|
|
const segmentCount = dashCount % 2 === 1 ? dashCount : dashCount + 1;
|
|
|
const lengthScale = 0.5 - (0.5 / 2 / segmentCount);
|
|
|
|
|
|
- const aromaticSegmentCount = 3;
|
|
|
+ const aromaticSegmentCount = aromaticDashCount + 1;
|
|
|
const aromaticLengthScale = 0.5 - (0.5 / 2 / aromaticSegmentCount);
|
|
|
const aromaticOffsetFactor = 4.5;
|
|
|
const multipleOffsetFactor = 3;
|