Skip to content

Commit

Permalink
Merge pull request #740 from dxdc/dashes
Browse files Browse the repository at this point in the history
Dashed bonds for bond order < 1 (revised)
  • Loading branch information
dkoes authored Dec 11, 2023
2 parents 2e1c453 + 84c512a commit 9b72fc9
Show file tree
Hide file tree
Showing 3 changed files with 47 additions and 29 deletions.
76 changes: 47 additions & 29 deletions src/GLModel.ts
Original file line number Diff line number Diff line change
Expand Up @@ -658,44 +658,52 @@ export class GLModel {
this.drawSphereImposter(geo, atom as XYZ, radius, C);
};

static drawDashedStickImposter(geo: Geometry, from: XYZ, to: XYZ, radius: number, color: Color, fromCap: CAP = 0, toCap: CAP = 0, dashLength: number = 0.1, gapLength: number = 0.25) {
var cylinderLength = Math.sqrt(Math.pow((from.x - to.x), 2) + Math.pow((from.y - to.y), 2) + Math.pow((from.z - to.z), 2));

// Constrain dash and gap lengths to not exceed cylinder length
dashLength = Math.min(dashLength, cylinderLength);
gapLength = Math.min(gapLength, cylinderLength);

// Initial calculations for totalSegments based on input dashLength, gapLength, and radius
var totalSegments = Math.floor(cylinderLength / (dashLength + gapLength + radius));

// Make totalSegments odd to ensure dashed segments at both ends
totalSegments += totalSegments % 2 === 0 ? 1 : 0;

private calculateDashes(from: XYZ, to: XYZ, radius: number, dashLength: number, gapLength: number) {
// Calculate the length of a cylinder defined by two points 'from' and 'to'.
var cylinderLength = Math.sqrt(
Math.pow((from.x - to.x), 2) +
Math.pow((from.y - to.y), 2) +
Math.pow((from.z - to.z), 2)
);

// Ensure non-negative values for radius, dashLength, and gapLength.
// Adjust gapLength to include the radius of the cylinder.
radius = Math.max(radius, 0);
gapLength = Math.max(gapLength, 0) + 2 * radius;
dashLength = Math.max(dashLength, 0.001);

// Handle cases where the combined length of dash and gap exceeds the cylinder's length.
// In such cases, use a single dash to represent the entire cylinder with no gaps.
if (dashLength + gapLength > cylinderLength) {
dashLength = cylinderLength;
gapLength = 0; // No gap as the dash fills the entire cylinder.
}

// Calculate the total number of dash-gap segments that can fit within the cylinder.
var totalSegments = Math.floor((cylinderLength - dashLength) / (dashLength + gapLength)) + 1;

// Compute the total length covered by dashes.
var totalDashLength = totalSegments * dashLength;

// If totalDashLength exceeds cylinder length, adjust it
if (totalDashLength > cylinderLength) {
totalSegments = Math.floor(cylinderLength / dashLength);
totalSegments -= totalSegments % 2 === 0 ? 1 : 0; // Make it odd
totalDashLength = totalSegments * dashLength; // Recalculate totalDashLength
}

// Recalculate gapLength based on final totalSegments and totalDashLength

// Recalculate gap length to evenly distribute remaining space among gaps.
// This ensures dashes and gaps are evenly spaced within the cylinder.
gapLength = (cylinderLength - totalDashLength) / totalSegments;

var new_to;
var new_from = new Vector3(from.x, from.y, from.z);
var new_to = new Vector3(to.x, to.y, to.z);

var gapVector = new Vector3((to.x - from.x) / (cylinderLength / gapLength), (to.y - from.y) / (cylinderLength / gapLength), (to.z - from.z) / (cylinderLength / gapLength));
var dashVector = new Vector3((to.x - from.x) / (cylinderLength / dashLength), (to.y - from.y) / (cylinderLength / dashLength), (to.z - from.z) / (cylinderLength / dashLength));

var segments = [];
for (var place = 0; place < totalSegments; place++) {
new_to = new Vector3(new_from.x + dashVector.x, new_from.y + dashVector.y, new_from.z + dashVector.z);
// this.intersectionShape.cylinder.push(new $3Dmol.Cylinder(new_from, new_to, radius));
GLModel.drawStickImposter(geo, new_from, new_to, radius, color);
segments.push({ from: new_from, to: new_to });
new_from = new Vector3(new_to.x + gapVector.x, new_to.y + gapVector.y, new_to.z + gapVector.z);
}
};

return segments;
}

static drawStickImposter(geo: Geometry, from: XYZ, to: XYZ, radius: number, color: Color, fromCap:CAP = 0, toCap:CAP = 0) {
//we need the four corners - two have from coord, two have to coord, the normal
Expand Down Expand Up @@ -790,10 +798,20 @@ export class GLModel {
if (!atom.capDrawn && atom.bonds.length < 4)
fromCap = 2;

var selectCylDrawMethod = function (bondOrder) {
if (geo.imposter) return (atomDashedBonds || bondOrder < 1) ? GLModel.drawDashedStickImposter : GLModel.drawStickImposter;
var selectCylDrawMethod = (bondOrder) => {
var drawMethod = geo.imposter ? GLModel.drawStickImposter : GLDraw.drawCylinder;

return GLDraw.drawCylinder; //mesh cylinder
if (!atomDashedBonds && bondOrder >= 1) {
return drawMethod;
}

// draw dashes
return (geo, from, to, radius, color, fromCap = 0, toCap = 0, dashLength = 0.1, gapLength = 0.25) => {
var segments = this.calculateDashes(from, to, radius, dashLength, gapLength);
segments.forEach(segment => {
drawMethod(geo, segment.from, segment.to, radius, color, fromCap, toCap);
});
};
};

for (i = 0; i < atom.bonds.length; i++) {
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.

0 comments on commit 9b72fc9

Please sign in to comment.