biojs-vis-pdbviewer
Version:
A BioJS 2.0 component to view protein structures
336 lines (328 loc) • 14.4 kB
JavaScript
Clazz.declarePackage ("J.renderspecial");
Clazz.load (["J.render.MeshRenderer", "JU.BS", "$.P3", "$.P3i", "$.V3"], "J.renderspecial.DrawRenderer", ["JU.A4", "$.M3", "$.Measure", "J.shapespecial.Draw", "JU.C", "$.GData"], function () {
c$ = Clazz.decorateAsClass (function () {
this.drawType = null;
this.dmesh = null;
this.controlHermites = null;
this.pt0 = null;
this.pt1 = null;
this.pt2 = null;
this.vTemp = null;
this.vTemp2 = null;
this.pt0f = null;
this.pt0i = null;
this.bsHandles = null;
Clazz.instantialize (this, arguments);
}, J.renderspecial, "DrawRenderer", J.render.MeshRenderer);
Clazz.prepareFields (c$, function () {
this.pt0 = new JU.P3 ();
this.pt1 = new JU.P3 ();
this.pt2 = new JU.P3 ();
this.vTemp = new JU.V3 ();
this.vTemp2 = new JU.V3 ();
this.pt0f = new JU.P3 ();
this.pt0i = new JU.P3i ();
this.bsHandles = new JU.BS ();
});
Clazz.overrideMethod (c$, "render",
function () {
this.needTranslucent = false;
this.imageFontScaling = this.vwr.getImageFontScaling ();
var draw = this.shape;
for (var i = draw.meshCount; --i >= 0; ) if (this.renderMesh (this.dmesh = draw.meshes[i])) this.renderInfo ();
return this.needTranslucent;
});
Clazz.overrideMethod (c$, "isPolygonDisplayable",
function (i) {
return J.shapespecial.Draw.isPolygonDisplayable (this.dmesh, i) && (this.dmesh.modelFlags == null || this.dmesh.bsMeshesVisible.get (i));
}, "~N");
Clazz.overrideMethod (c$, "renderMesh",
function (mesh) {
if (mesh.connections != null) {
if (mesh.connections[0] < 0) return false;
mesh.vs = new Array (4);
mesh.vc = 4;
var c = mesh.connections;
for (var i = 0; i < 4; i++) {
mesh.vs[i] = (c[i] < 0 ? mesh.vs[i - 1] : this.vwr.getAtomPoint3f (c[i]));
}
mesh.recalcAltVertices = true;
}return this.renderMesh2 (mesh);
}, "J.shape.Mesh");
Clazz.overrideMethod (c$, "render2",
function (isExport) {
this.drawType = this.dmesh.drawType;
this.diameter = this.dmesh.diameter;
this.width = this.dmesh.width;
if (this.mesh.connections != null) this.getConnectionPoints ();
if (this.mesh.lineData != null) {
this.drawLineData (this.mesh.lineData);
return;
}var isDrawPickMode = (this.vwr.getPickingMode () == 4);
var nPoints = this.vertexCount;
var isCurved = ((this.drawType === J.shapespecial.Draw.EnumDrawType.CURVE || this.drawType === J.shapespecial.Draw.EnumDrawType.ARROW || this.drawType === J.shapespecial.Draw.EnumDrawType.ARC) && this.vertexCount >= 2);
var isSegments = (this.drawType === J.shapespecial.Draw.EnumDrawType.LINE_SEGMENT);
if (this.width > 0 && isCurved) {
this.pt1f.set (0, 0, 0);
var n = (this.drawType === J.shapespecial.Draw.EnumDrawType.ARC ? 2 : this.vertexCount);
for (var i = 0; i < n; i++) this.pt1f.add (this.vertices[i]);
this.pt1f.scale (1 / n);
this.tm.transformPtScr (this.pt1f, this.pt1i);
this.diameter = Clazz.floatToInt (this.vwr.tm.scaleToScreen (this.pt1i.z, Clazz.doubleToInt (Math.floor (this.width * 1000))));
if (this.diameter == 0) this.diameter = 1;
}if ((this.dmesh.isVector) && this.dmesh.haveXyPoints) {
var ptXY = 0;
for (var i = 0; i < 2; i++) if (this.vertices[i].z == 3.4028235E38 || this.vertices[i].z == -3.4028235E38) ptXY += i + 1;
if (--ptXY < 2) {
this.renderXyArrow (ptXY);
return;
}}var tension = 5;
switch (this.drawType) {
default:
this.render2b (false);
break;
case J.shapespecial.Draw.EnumDrawType.CIRCULARPLANE:
if (this.dmesh.scale > 0) this.width *= this.dmesh.scale;
this.render2b (false);
break;
case J.shapespecial.Draw.EnumDrawType.CIRCLE:
this.tm.transformPtScr (this.vertices[0], this.pt1i);
if (this.diameter == 0 && this.width == 0) this.width = 1.0;
if (this.dmesh.scale > 0) this.width *= this.dmesh.scale;
if (this.width > 0) this.diameter = Clazz.floatToInt (this.vwr.tm.scaleToScreen (this.pt1i.z, Clazz.doubleToInt (Math.floor (this.width * 1000))));
if (this.diameter > 0 && (this.mesh.drawTriangles || this.mesh.fillTriangles)) {
this.g3d.addRenderer (1073741880);
this.g3d.drawFilledCircle (this.colix, this.mesh.fillTriangles ? this.colix : 0, this.diameter, this.pt1i.x, this.pt1i.y, this.pt1i.z);
}break;
case J.shapespecial.Draw.EnumDrawType.CURVE:
case J.shapespecial.Draw.EnumDrawType.LINE_SEGMENT:
break;
case J.shapespecial.Draw.EnumDrawType.ARC:
var nDegreesOffset = (this.vertexCount > 3 ? this.vertices[3].x : 0);
var theta = (this.vertexCount > 3 ? this.vertices[3].y : 360);
if (theta == 0) return;
var fractionalOffset = (this.vertexCount > 3 ? this.vertices[3].z : 0);
this.vTemp.sub2 (this.vertices[1], this.vertices[0]);
this.pt1f.scaleAdd2 (fractionalOffset, this.vTemp, this.vertices[0]);
var mat = new JU.M3 ().setAA (JU.A4.newVA (this.vTemp, (nDegreesOffset * 3.141592653589793 / 180)));
this.vTemp2.sub2 (this.vertexCount > 2 ? this.vertices[2] : J.shapespecial.Draw.randomPoint (), this.vertices[0]);
this.vTemp2.cross (this.vTemp, this.vTemp2);
this.vTemp2.cross (this.vTemp2, this.vTemp);
this.vTemp2.normalize ();
this.vTemp2.scale (this.dmesh.scale / 2);
mat.rotate (this.vTemp2);
var degrees = theta / 5;
while (Math.abs (degrees) > 5) degrees /= 2;
nPoints = Math.round (theta / degrees) + 1;
while (nPoints < 10) {
degrees /= 2;
nPoints = Math.round (theta / degrees) + 1;
}
mat.setAA (JU.A4.newVA (this.vTemp, (degrees * 3.141592653589793 / 180)));
this.screens = this.vwr.allocTempScreens (nPoints);
var iBase = nPoints - (this.dmesh.scale < 2 ? 3 : 3);
for (var i = 0; i < nPoints; i++) {
if (i == iBase) this.pt0.setT (this.pt1);
this.pt1.scaleAdd2 (1, this.vTemp2, this.pt1f);
if (i == 0) this.pt2.setT (this.pt1);
this.tm.transformPtScr (this.pt1, this.screens[i]);
mat.rotate (this.vTemp2);
}
if (this.dmesh.isVector && !this.dmesh.noHead) {
this.renderArrowHead (this.pt0, this.pt1, 0.3, false, false, this.dmesh.isBarb);
this.tm.transformPtScr (this.pt1f, this.screens[nPoints - 1]);
}this.pt1f.setT (this.pt2);
break;
case J.shapespecial.Draw.EnumDrawType.ARROW:
if (this.vertexCount == 2) {
this.renderArrowHead (this.vertices[0], this.vertices[1], 0, false, true, this.dmesh.isBarb);
break;
}var nHermites = 5;
if (this.controlHermites == null || this.controlHermites.length < nHermites + 1) {
this.controlHermites = new Array (nHermites + 1);
}JU.GData.getHermiteList (tension, this.vertices[this.vertexCount - 3], this.vertices[this.vertexCount - 2], this.vertices[this.vertexCount - 1], this.vertices[this.vertexCount - 1], this.vertices[this.vertexCount - 1], this.controlHermites, 0, nHermites, true);
this.renderArrowHead (this.controlHermites[nHermites - 2], this.controlHermites[nHermites - 1], 0, false, false, this.dmesh.isBarb);
break;
}
if (this.diameter == 0) this.diameter = 3;
if (isCurved) {
this.g3d.addRenderer (553648147);
for (var i = 0, i0 = 0; i < nPoints - 1; i++) {
this.g3d.fillHermite (tension, this.diameter, this.diameter, this.diameter, this.screens[i0], this.screens[i], this.screens[i + 1], this.screens[i + (i == nPoints - 2 ? 1 : 2)]);
i0 = i;
}
} else if (isSegments) {
for (var i = 0; i < nPoints - 1; i++) this.drawLine (i, i + 1, true, this.vertices[i], this.vertices[i + 1], this.screens[i], this.screens[i + 1]);
}if (isDrawPickMode && !isExport) {
this.renderHandles ();
}}, "~B");
Clazz.defineMethod (c$, "getConnectionPoints",
function () {
this.vertexCount = 3;
var dmax = 3.4028235E38;
var i0 = 0;
var j0 = 0;
for (var i = 0; i < 2; i++) for (var j = 2; j < 4; j++) {
var d = this.vertices[i].distance (this.vertices[j]);
if (d < dmax) {
dmax = d;
i0 = i;
j0 = j;
}}
this.pt0.ave (this.vertices[0], this.vertices[1]);
this.pt2.ave (this.vertices[2], this.vertices[3]);
this.pt1.ave (this.pt0, this.pt2);
this.vertices[3] = JU.P3.newP (this.vertices[i0]);
this.vertices[3].add (this.vertices[j0]);
this.vertices[3].scale (0.5);
this.vertices[1] = JU.P3.newP (this.pt1);
this.vertices[0] = JU.P3.newP (this.pt0);
this.vertices[2] = JU.P3.newP (this.pt2);
for (var i = 0; i < 4; i++) this.tm.transformPtScr (this.vertices[i], this.screens[i]);
var f = 4 * this.getArrowScale ();
var endoffset = 0.2;
var offsetside = (this.width == 0 ? 0.1 : this.width);
this.pt0.set (this.screens[0].x, this.screens[0].y, this.screens[0].z);
this.pt1.set (this.screens[1].x, this.screens[1].y, this.screens[1].z);
this.pt2.set (this.screens[3].x, this.screens[3].y, this.screens[3].z);
var dx = (this.screens[1].x - this.screens[0].x) * f;
var dy = (this.screens[1].y - this.screens[0].y) * f;
if (dmax == 0 || JU.Measure.computeTorsion (this.pt2, this.pt0, JU.P3.new3 (this.pt0.x, this.pt0.y, 10000), this.pt1, false) > 0) {
dx = -dx;
dy = -dy;
}this.pt2.set (dy, -dx, 0);
this.pt1.add (this.pt2);
this.tm.unTransformPoint (this.pt1, this.vertices[1]);
this.pt2.scale (offsetside);
this.vTemp.sub2 (this.vertices[1], this.vertices[0]);
this.vTemp.scale (endoffset);
this.vertices[0].add (this.vTemp);
this.vTemp.sub2 (this.vertices[1], this.vertices[2]);
this.vTemp.scale (endoffset);
this.vertices[2].add (this.vTemp);
for (var i = 0; i < 3; i++) {
this.tm.transformPtScr (this.vertices[i], this.screens[i]);
if (offsetside != 0) {
this.screens[i].x += Math.round (this.pt2.x);
this.screens[i].y += Math.round (this.pt2.y);
this.pt1.set (this.screens[i].x, this.screens[i].y, this.screens[i].z);
this.tm.unTransformPoint (this.pt1, this.vertices[i]);
}}
});
Clazz.defineMethod (c$, "drawLineData",
function (lineData) {
if (this.diameter == 0) this.diameter = 3;
for (var i = lineData.size (); --i >= 0; ) {
var pts = lineData.get (i);
this.tm.transformPtScr (pts[0], this.pt1i);
this.tm.transformPtScr (pts[1], this.pt2i);
this.drawLine (-1, -2, true, pts[0], pts[1], this.pt1i, this.pt2i);
}
}, "JU.Lst");
Clazz.defineMethod (c$, "renderXyArrow",
function (ptXY) {
var ptXYZ = 1 - ptXY;
var arrowPt = new Array (2);
arrowPt[ptXYZ] = this.pt1;
arrowPt[ptXY] = this.pt0;
this.pt0.set (this.screens[ptXY].x, this.screens[ptXY].y, this.screens[ptXY].z);
this.tm.rotatePoint (this.vertices[ptXYZ], this.pt1);
this.pt1.z *= -1;
var zoomDimension = this.vwr.getScreenDim ();
var scaleFactor = zoomDimension / 20;
this.pt1.scaleAdd2 (this.dmesh.scale * scaleFactor, this.pt1, this.pt0);
if (this.diameter == 0) this.diameter = 1;
this.pt1i.set (Math.round (this.pt0.x), Math.round (this.pt0.y), Math.round (this.pt0.z));
this.pt2i.set (Math.round (this.pt1.x), Math.round (this.pt1.y), Math.round (this.pt1.z));
if (this.diameter < 0) this.g3d.drawDottedLine (this.pt1i, this.pt2i);
else this.g3d.fillCylinder (2, this.diameter, this.pt1i, this.pt2i);
this.renderArrowHead (this.pt0, this.pt1, 0, true, false, false);
}, "~N");
Clazz.defineMethod (c$, "renderArrowHead",
function (pt1, pt2, factor2, isTransformed, withShaft, isBarb) {
if (this.dmesh.noHead) return;
var fScale = this.getArrowScale ();
if (isTransformed) fScale *= 40;
if (factor2 > 0) fScale *= factor2;
this.pt0f.setT (pt1);
this.pt2f.setT (pt2);
var d = this.pt0f.distance (this.pt2f);
if (d == 0) return;
this.vTemp.sub2 (this.pt2f, this.pt0f);
this.vTemp.normalize ();
this.vTemp.scale (fScale / 5);
if (!withShaft) this.pt2f.add (this.vTemp);
this.vTemp.scale (5);
this.pt1f.sub2 (this.pt2f, this.vTemp);
if (isTransformed) {
this.pt1i.set (Math.round (this.pt1f.x), Math.round (this.pt1f.y), Math.round (this.pt1f.z));
this.pt2i.set (Math.round (this.pt2f.x), Math.round (this.pt2f.y), Math.round (this.pt2f.z));
} else {
this.tm.transformPtScr (this.pt2f, this.pt2i);
this.tm.transformPtScr (this.pt1f, this.pt1i);
this.tm.transformPtScr (this.pt0f, this.pt0i);
}if (this.pt2i.z == 1 || this.pt1i.z == 1) return;
var headDiameter;
if (this.diameter > 0) {
headDiameter = this.diameter * 3;
} else {
this.vTemp.set (this.pt2i.x - this.pt1i.x, this.pt2i.y - this.pt1i.y, this.pt2i.z - this.pt1i.z);
headDiameter = Math.round (this.vTemp.length () * .5);
this.diameter = Clazz.doubleToInt (headDiameter / 5);
}if (this.diameter < 1) this.diameter = 1;
if (headDiameter > 2) this.g3d.fillConeScreen (2, headDiameter, this.pt1i, this.pt2i, isBarb);
if (withShaft) this.g3d.fillCylinderScreen3I (4, this.diameter, this.pt0i, this.pt1i, null, null, 0);
}, "JU.T3,JU.T3,~N,~B,~B,~B");
Clazz.defineMethod (c$, "getArrowScale",
function () {
var fScale = (this.dmesh.isScaleSet ? this.dmesh.scale : 0);
if (fScale == 0) fScale = this.vwr.getFloat (570425352) * (this.dmesh.connections == null ? 1 : 0.5);
if (fScale <= 0) fScale = 0.5;
return fScale;
});
Clazz.defineMethod (c$, "renderHandles",
function () {
var diameter = Math.round (10 * this.imageFontScaling);
switch (this.drawType) {
case J.shapespecial.Draw.EnumDrawType.NONE:
return;
default:
var colixFill = JU.C.getColixTranslucent3 (23, true, 0.5);
this.bsHandles.clearAll ();
this.g3d.addRenderer (1073741880);
for (var i = this.dmesh.pc; --i >= 0; ) {
if (!this.isPolygonDisplayable (i)) continue;
var vertexIndexes = this.dmesh.pis[i];
if (vertexIndexes == null) continue;
for (var j = (this.dmesh.isTriangleSet ? 3 : vertexIndexes.length); --j >= 0; ) {
var k = vertexIndexes[j];
if (this.bsHandles.get (k)) continue;
this.bsHandles.set (k);
this.g3d.drawFilledCircle (23, colixFill, diameter, this.screens[k].x, this.screens[k].y, this.screens[k].z);
}
}
break;
}
});
Clazz.defineMethod (c$, "renderInfo",
function () {
if (this.mesh.title == null || this.vwr.getDrawHover () || !this.g3d.setC (this.vwr.getColixBackgroundContrast ())) return;
for (var i = this.dmesh.pc; --i >= 0; ) if (this.isPolygonDisplayable (i)) {
var size = this.vwr.getFloat (570425356);
if (size <= 0) size = 14;
var fid = this.g3d.getFontFid (size * this.imageFontScaling);
this.g3d.setFontFid (fid);
var s = this.mesh.title[i < this.mesh.title.length ? i : this.mesh.title.length - 1];
var pt = 0;
if (s.length > 1 && s.charAt (0) == '>') {
pt = this.dmesh.pis[i].length - 1;
s = s.substring (1);
if (this.drawType === J.shapespecial.Draw.EnumDrawType.ARC) this.pt1f.setT (this.pt2f);
}if (this.drawType !== J.shapespecial.Draw.EnumDrawType.ARC) this.pt1f.setT (this.vertices[this.dmesh.pis[i][pt]]);
this.tm.transformPtScr (this.pt1f, this.pt1i);
var offset = Math.round (5 * this.imageFontScaling);
this.g3d.drawString (s, null, this.pt1i.x + offset, this.pt1i.y - offset, this.pt1i.z, this.pt1i.z, 0);
break;
}
});
});