Skip to content

Commit

Permalink
Merge branch 'master' of github.com:3dmol/3Dmol.js
Browse files Browse the repository at this point in the history
  • Loading branch information
dkoes committed Jan 13, 2024
2 parents e71629b + b038d7b commit 3c50910
Show file tree
Hide file tree
Showing 7 changed files with 156 additions and 11 deletions.
91 changes: 83 additions & 8 deletions src/GLModel.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import { Sphere, Cylinder } from "./WebGL/shapes";
import { Vector3, Matrix4, conversionMatrix3, Matrix3, XYZ } from "./WebGL/math";
import { Color, CC, ColorschemeSpec, ColorSpec } from "./colors";
import { InstancedMaterial, SphereImposterMaterial, MeshLambertMaterial, Object3D, Mesh, LineBasicMaterial, Line, LineStyle } from "./WebGL";
import { GLDraw } from "./GLDraw"
import { CAP, GLDraw } from "./GLDraw"
import { CartoonStyleSpec, drawCartoon } from "./glcartoon";
import { elementColors } from "./colors";
import { get, deepCopy, extend, getExtent, getAtomProperty, makeFunction, getPropertyRange, specStringToObject, getbin, getColorFromStyle } from "./utilities";
Expand Down Expand Up @@ -658,8 +658,54 @@ export class GLModel {
this.drawSphereImposter(geo, atom as XYZ, radius, C);
};

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;

// 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 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);
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) {
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
//is the opposing point, from which we can get the normal and length
//also need the radius
Expand Down Expand Up @@ -735,8 +781,12 @@ export class GLModel {
var doubleBondScale = style.doubleBondScaling || 0.4;
var tripleBondScale = style.tripleBondScaling || 0.25;

var bondDashLength = style.dashedBondConfig?.dashLength || 0.1;
var bondGapLength = style.dashedBondConfig?.gapLength || 0.25;

var bondR = atomBondR;
var atomSingleBond = style.singleBonds || false;
var atomDashedBonds = style.dashedBonds || false;
var fromCap = 0, toCap = 0;
var atomneedsi, atom2needsi, i, singleBond, bstyle;
var cylinder1a, cylinder1b, cylinder1c, cylinder2a, cylinder2b, cylinder2c;
Expand All @@ -748,12 +798,24 @@ export class GLModel {
if (!atom.capDrawn && atom.bonds.length < 4)
fromCap = 2;

var drawCyl = GLDraw.drawCylinder; //mesh cylinder
if (geo.imposter)
drawCyl = GLModel.drawStickImposter;
var selectCylDrawMethod = (bondOrder) => {
var drawMethod = geo.imposter ? GLModel.drawStickImposter : GLDraw.drawCylinder;

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++) {
var drawCyl = selectCylDrawMethod(atom.bondOrder[i]);
var j = atom.bonds[i]; // our neighbor
var atom2 = atoms[j]; //parsePDB, etc should only add defined bonds
mp = mp2 = mp3 = null;
Expand Down Expand Up @@ -797,10 +859,10 @@ export class GLModel {
if (C1 != C2) {
mp = new Vector3().addVectors(p1, p2)
.multiplyScalar(0.5);
drawCyl(geo, p1, mp, bondR, C1, fromCap, 0);
drawCyl(geo, mp, p2, bondR, C2, 0, toCap);
drawCyl(geo, p1, mp, bondR, C1, fromCap, 0, bondDashLength, bondGapLength);
drawCyl(geo, mp, p2, bondR, C2, 0, toCap, bondDashLength, bondGapLength);
} else {
drawCyl(geo, p1, p2, bondR, C1, fromCap, toCap);
drawCyl(geo, p1, p2, bondR, C1, fromCap, toCap, bondDashLength, bondGapLength);
}


Expand Down Expand Up @@ -2868,6 +2930,15 @@ export interface CrossStyleSpec {
opacity?: number;
}

/** Dashed Bond style specification
*/
export interface DashedBondSpec {
/** length of dash (default 0.1) */
dashLength?: number;
/** length of gap (default 0.25) */
gapLength?: number;
}

/** Stick (cylinder) style specification
*/
export interface StickStyleSpec {
Expand All @@ -2879,6 +2950,10 @@ export interface StickStyleSpec {
doubleBondScaling?: number;
/** radius scaling factor for drawing triple bonds (default 0.25) */
tripleBondScaling?: number;
/** dashed bond properties */
dashedBondConfig?: DashedBondSpec;
/** draw all bonds as dashed bonds */
dashedBonds?: boolean;
/** draw all bonds as single bonds */
singleBonds?: boolean;
/** colorscheme to use on atoms; overrides color */
Expand Down
35 changes: 35 additions & 0 deletions tests/auto/tests/partialbonds2.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@

/*@div
<div style="width: 400px; height: 400px; position: relative;"
class='viewer_3Dmoljs'
data-element='moldata'
data-backgroundcolor='0xffffff'
data-style='stick'
data-type="sdf"></div>
*/

/*
@data
<textarea style="display: none;" id="moldata">
Molecule002
Mrv1903 01162316393D
6 5 0 0 0 0 999 V2000
0.4761 0.1839 -0.9563 H 0 0 0 0 0 0 0 0 0 0 0 0
0.1475 -0.2251 0.0075 C 0 0 0 0 0 0 0 0 0 0 0 0
-0.8612 -0.6549 0.0499 H 0 0 0 0 0 0 0 0 0 0 0 0
0.5167 0.2726 0.9131 H 0 0 0 0 0 0 0 0 0 0 0 0
1.3194 -2.0204 0.0676 Cl 0 0 0 0 0 0 0 0 0 0 0 0
-1.5985 2.4439 -0.0818 Br 0 0 0 0 0 0 0 0 0 0 0 0
1 2 8 0 0 0 0
2 4 8 0 0 0 0
2 3 8 0 0 0 0
2 6 0.5 0 0 0 0
2 5 0.03 0 0 0 0
M END
> <anyBondsFromCoords>
true
$$$$
</textarea>
*/
35 changes: 35 additions & 0 deletions tests/auto/tests/partialbonds3.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@

/*@div
<div style="width: 400px; height: 400px; position: relative;"
class='viewer_3Dmoljs'
data-element='moldata'
data-backgroundcolor='0xffffff'
data-style='{"stick":{"dashedBonds": true, "dashedBondConfig": { "dashLength": 0.01, "gapLength": 0.05 }}}'
data-type="sdf"></div>
*/

/*
@data
<textarea style="display: none;" id="moldata">
Molecule002
Mrv1903 01162316393D
6 5 0 0 0 0 999 V2000
0.4761 0.1839 -0.9563 H 0 0 0 0 0 0 0 0 0 0 0 0
0.1475 -0.2251 0.0075 C 0 0 0 0 0 0 0 0 0 0 0 0
-0.8612 -0.6549 0.0499 H 0 0 0 0 0 0 0 0 0 0 0 0
0.5167 0.2726 0.9131 H 0 0 0 0 0 0 0 0 0 0 0 0
1.3194 -2.0204 0.0676 Cl 0 0 0 0 0 0 0 0 0 0 0 0
-1.5985 2.4439 -0.0818 Br 0 0 0 0 0 0 0 0 0 0 0 0
1 2 8 0 0 0 0
2 4 8 0 0 0 0
2 3 8 0 0 0 0
2 6 0.5 0 0 0 0
2 5 0.03 0 0 0 0
M END
> <anyBondsFromCoords>
true
$$$$
</textarea>
*/
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.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
6 changes: 3 additions & 3 deletions tutorials/code.md
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ To make sure everything works, we are going to add a sphere, set the camera, ren
</script>
```

Documentation: [$3Dmol.createViewer()]($3Dmol.html#createViewer)
Documentation: [$3Dmol.createViewer()](global.html#createViewer)

<div class="align-center">
<button id="btn-01" class="btn btn-primary">Try it</button>
Expand Down Expand Up @@ -96,7 +96,7 @@ jQuery(function() {

If this has worked, you should see a rather fetching green ball in front of an orange background. If not, then now's a good time to get familiar with the developer console on your favourite browser and check for typos ([Firefox](https://developer.mozilla.org/en/docs/Tools/Web_Console), [Chrome](https://developers.google.com/web/tools/chrome-devtools/), ...)

Note, the ```viewer``` variable now contains an instance of GLViewer and we use the [$3Dmol.GLViewer API]($3Dmol.GLViewer) to change the orange background white.
Note, the ```viewer``` variable now contains an instance of GLViewer and we use the [$3Dmol.GLViewer API](GLViewer.html) to change the orange background white.

```
viewer.setBackgroundColor('white');
Expand All @@ -106,7 +106,7 @@ Note, the ```viewer``` variable now contains an instance of GLViewer and we use
<button id="btn-01-alt" class="btn btn-primary">Try it</button>
</div>

Documentation: [$3Dmol.GLViewer API]($3Dmol.GLViewer)
Documentation: [$3Dmol.GLViewer API](GLViewer.html)

### Loading data dynamically

Expand Down

0 comments on commit 3c50910

Please sign in to comment.