biojs-vis-pdbviewer
Version:
A BioJS 2.0 component to view protein structures
463 lines (462 loc) • 16.7 kB
JavaScript
Clazz.declarePackage ("J.g3d");
Clazz.load (["JU.P3"], "J.g3d.SphereRenderer", ["JU.GData"], function () {
c$ = Clazz.decorateAsClass (function () {
this.g3d = null;
this.shader = null;
this.minX = 0;
this.maxX = 0;
this.minY = 0;
this.maxY = 0;
this.minZ = 0;
this.maxZ = 0;
this.x = 0;
this.y = 0;
this.z = 0;
this.diameter = 0;
this.tScreened = false;
this.shades = null;
this.zroot = null;
this.mat = null;
this.coef = null;
this.mDeriv = null;
this.selectedOctant = 0;
this.octantPoints = null;
this.planeShade = 0;
this.zbuf = null;
this.width = 0;
this.height = 0;
this.depth = 0;
this.slab = 0;
this.offsetPbufBeginLine = 0;
this.addAllPixels = false;
this.ptTemp = null;
this.planeShades = null;
this.dxyz = null;
this.z0 = 0;
Clazz.instantialize (this, arguments);
}, J.g3d, "SphereRenderer");
Clazz.prepareFields (c$, function () {
this.zroot = Clazz.newDoubleArray (2, 0);
this.ptTemp = new JU.P3 ();
this.planeShades = Clazz.newIntArray (3, 0);
this.dxyz = Clazz.newFloatArray (3, 3, 0);
});
Clazz.makeConstructor (c$,
function (g3d) {
this.g3d = g3d;
this.shader = g3d.shader;
}, "J.g3d.Graphics3D");
Clazz.defineMethod (c$, "render",
function (shades, tScreened, diameter, x, y, z, mat, coef, mDeriv, selectedOctant, octantPoints, addAllPixels) {
if (z == 1) return;
this.width = this.g3d.width;
this.height = this.g3d.height;
if (diameter > 49) diameter &= -2;
if (this.g3d.isClippedXY (diameter, x, y)) return;
var radius = (diameter + 1) >> 1;
this.minX = x - radius;
this.maxX = x + radius;
this.minY = y - radius;
this.maxY = y + radius;
this.slab = this.g3d.slab;
this.depth = this.g3d.depth;
this.minZ = z - radius;
this.maxZ = z + radius;
if (this.maxZ < this.slab || this.minZ > this.depth) return;
this.shader.nOut = this.shader.nIn = 0;
this.zbuf = this.g3d.zbuf;
this.addAllPixels = addAllPixels;
this.offsetPbufBeginLine = this.width * y + x;
this.x = x;
this.y = y;
this.z = z;
this.diameter = diameter;
this.tScreened = tScreened;
this.shades = shades;
this.mat = mat;
if (mat != null) {
this.coef = coef;
this.mDeriv = mDeriv;
this.selectedOctant = selectedOctant;
this.octantPoints = octantPoints;
}if (mat != null || diameter > 128) {
this.renderLarge ();
if (mat != null) {
this.mat = null;
this.coef = null;
this.mDeriv = null;
this.octantPoints = null;
}} else {
var ss = this.shader.sphereShapeCache[diameter - 1];
if (ss == null) ss = this.createSphereShape (diameter);
if (this.minX < 0 || this.maxX >= this.width || this.minY < 0 || this.maxY >= this.height || this.minZ < this.slab || z > this.depth) this.renderShapeClipped (ss, x, y, z, diameter);
else this.renderShapeUnclipped (ss, x, y, z, diameter);
}this.shades = null;
this.zbuf = null;
}, "~A,~B,~N,~N,~N,~N,JU.M3,~A,JU.M4,~N,~A,~B");
Clazz.defineMethod (c$, "createSphereShape",
function (diameter) {
var shader = this.shader;
var countSE = 0;
var oddDiameter = (diameter & 1) != 0;
var radiusF = diameter / 2.0;
var radiusF2 = radiusF * radiusF;
var radius = Clazz.doubleToInt ((diameter + 1) / 2);
var y = oddDiameter ? 0 : 0.5;
for (var i = 0; i < radius; ++i, ++y) {
var y2 = y * y;
var x = oddDiameter ? 0 : 0.5;
for (var j = 0; j < radius; ++j, ++x) {
var x2 = x * x;
var z2 = radiusF2 - y2 - x2;
if (z2 >= 0) ++countSE;
}
}
var sphereShape = Clazz.newIntArray (countSE, 0);
var offset = 0;
y = oddDiameter ? 0 : 0.5;
for (var i = 0; i < radius; ++i, ++y) {
var y2 = y * y;
var x = oddDiameter ? 0 : 0.5;
for (var j = 0; j < radius; ++j, ++x) {
var x2 = x * x;
var z2 = radiusF2 - y2 - x2;
if (z2 >= 0) {
var z = Math.sqrt (z2);
var height = Clazz.floatToInt (z);
var shadeIndexSE = shader.getShadeN (x, y, z, radiusF);
var shadeIndexSW = shader.getShadeN (-x, y, z, radiusF);
var shadeIndexNE = shader.getShadeN (x, -y, z, radiusF);
var shadeIndexNW = shader.getShadeN (-x, -y, z, radiusF);
var packed = (height | (shadeIndexSE << 7) | (shadeIndexSW << 13) | (shadeIndexNE << 19) | (shadeIndexNW << 25));
sphereShape[offset++] = packed;
}}
sphereShape[offset - 1] |= 0x80000000;
}
return shader.sphereShapeCache[diameter - 1] = sphereShape;
}, "~N");
Clazz.defineMethod (c$, "renderShapeUnclipped",
function (sphereShape, x, y, z, diameter) {
var offsetSphere = 0;
var evenSizeCorrection = 1 - (diameter & 1);
var offsetSouthCenter = this.offsetPbufBeginLine;
var offsetNorthCenter = offsetSouthCenter - evenSizeCorrection * this.width;
var nLines = Clazz.doubleToInt ((diameter + 1) / 2);
var shades = this.shades;
var g3d = this.g3d;
var zbuf = this.zbuf;
var width = this.width;
if (!this.tScreened) {
do {
var offsetSE = offsetSouthCenter;
var offsetSW = offsetSouthCenter - evenSizeCorrection;
var offsetNE = offsetNorthCenter;
var offsetNW = offsetNorthCenter - evenSizeCorrection;
var packed;
do {
packed = sphereShape[offsetSphere++];
var zPixel = z - (packed & 0x7F);
if (zPixel < zbuf[offsetSE]) g3d.addPixel (offsetSE, zPixel, shades[((packed >> 7) & 0x3F)]);
if (zPixel < zbuf[offsetSW]) g3d.addPixel (offsetSW, zPixel, shades[((packed >> 13) & 0x3F)]);
if (zPixel < zbuf[offsetNE]) g3d.addPixel (offsetNE, zPixel, shades[((packed >> 19) & 0x3F)]);
if (zPixel < zbuf[offsetNW]) g3d.addPixel (offsetNW, zPixel, shades[((packed >> 25) & 0x3F)]);
++offsetSE;
--offsetSW;
++offsetNE;
--offsetNW;
} while (packed >= 0);
offsetSouthCenter += width;
offsetNorthCenter -= width;
} while (--nLines > 0);
return;
}var flipflopSouthCenter = (x ^ y) & 1;
var flipflopNorthCenter = flipflopSouthCenter ^ evenSizeCorrection;
var flipflopSE = flipflopSouthCenter;
var flipflopSW = flipflopSouthCenter ^ evenSizeCorrection;
var flipflopNE = flipflopNorthCenter;
var flipflopNW = flipflopNorthCenter ^ evenSizeCorrection;
var flipflopsCenter = flipflopSE | (flipflopSW << 1) | (flipflopNE << 2) | (flipflopNW << 3);
do {
var offsetSE = offsetSouthCenter;
var offsetSW = offsetSouthCenter - evenSizeCorrection;
var offsetNE = offsetNorthCenter;
var offsetNW = offsetNorthCenter - evenSizeCorrection;
var packed;
var flipflops = (flipflopsCenter = ~flipflopsCenter);
do {
packed = sphereShape[offsetSphere++];
var zPixel = z - (packed & 0x7F);
if ((flipflops & 1) != 0 && zPixel < zbuf[offsetSE]) g3d.addPixel (offsetSE, zPixel, shades[((packed >> 7) & 0x3F)]);
if ((flipflops & 2) != 0 && zPixel < zbuf[offsetSW]) g3d.addPixel (offsetSW, zPixel, shades[((packed >> 13) & 0x3F)]);
if ((flipflops & 4) != 0 && zPixel < zbuf[offsetNE]) g3d.addPixel (offsetNE, zPixel, shades[((packed >> 19) & 0x3F)]);
if ((flipflops & 8) != 0 && zPixel < zbuf[offsetNW]) g3d.addPixel (offsetNW, zPixel, shades[((packed >> 25) & 0x3F)]);
++offsetSE;
--offsetSW;
++offsetNE;
--offsetNW;
flipflops = ~flipflops;
} while (packed >= 0);
offsetSouthCenter += width;
offsetNorthCenter -= width;
} while (--nLines > 0);
}, "~A,~N,~N,~N,~N");
Clazz.defineMethod (c$, "renderShapeClipped",
function (sphereShape, x, y, z, diameter) {
var offsetSphere = 0;
var evenSizeCorrection = 1 - (diameter & 1);
var offsetSouthCenter = this.offsetPbufBeginLine;
var offsetNorthCenter = offsetSouthCenter - evenSizeCorrection * this.width;
var nLines = Clazz.doubleToInt ((diameter + 1) / 2);
var ySouth = y;
var yNorth = y - evenSizeCorrection;
var randu = (x << 16) + (y << 1) ^ 0x33333333;
var flipflopSouthCenter = (x ^ y) & 1;
var flipflopNorthCenter = flipflopSouthCenter ^ evenSizeCorrection;
var flipflopSE = flipflopSouthCenter;
var flipflopSW = flipflopSouthCenter ^ evenSizeCorrection;
var flipflopNE = flipflopNorthCenter;
var flipflopNW = flipflopNorthCenter ^ evenSizeCorrection;
var flipflopsCenter = flipflopSE | (flipflopSW << 1) | (flipflopNE << 2) | (flipflopNW << 3);
var shades = this.shades;
var g3d = this.g3d;
var zbuf = this.zbuf;
do {
var tSouthVisible = ySouth >= 0 && ySouth < this.height;
var tNorthVisible = yNorth >= 0 && yNorth < this.height;
var offsetSE = offsetSouthCenter;
var offsetSW = offsetSouthCenter - evenSizeCorrection;
var offsetNE = offsetNorthCenter;
var offsetNW = offsetNorthCenter - evenSizeCorrection;
var packed;
var flipflops = (flipflopsCenter = ~flipflopsCenter);
var xEast = x;
var xWest = x - evenSizeCorrection;
do {
var tWestVisible = xWest >= 0 && xWest < this.width;
var tEastVisible = xEast >= 0 && xEast < this.width;
packed = sphereShape[offsetSphere++];
var isCore;
var zOffset = packed & 0x7F;
var zPixel;
if (z < this.slab) {
zPixel = z + zOffset;
isCore = (zPixel >= this.slab);
} else {
zPixel = z - zOffset;
isCore = (zPixel < this.slab);
}if (isCore) zPixel = this.slab;
if (zPixel >= this.slab && zPixel <= this.depth) {
if (tSouthVisible) {
if (tEastVisible && (this.addAllPixels || (flipflops & 1) != 0) && zPixel < zbuf[offsetSE]) {
var i = (isCore ? 44 + ((randu >> 7) & 0x07) : (packed >> 7) & 0x3F);
g3d.addPixel (offsetSE, zPixel, shades[i]);
}if (tWestVisible && (this.addAllPixels || (flipflops & 2) != 0) && zPixel < zbuf[offsetSW]) {
var i = (isCore ? 44 + ((randu >> 13) & 0x07) : (packed >> 13) & 0x3F);
g3d.addPixel (offsetSW, zPixel, shades[i]);
}}if (tNorthVisible) {
if (tEastVisible && (!this.tScreened || (flipflops & 4) != 0) && zPixel < zbuf[offsetNE]) {
var i = (isCore ? 44 + ((randu >> 19) & 0x07) : (packed >> 19) & 0x3F);
g3d.addPixel (offsetNE, zPixel, shades[i]);
}if (tWestVisible && (!this.tScreened || (flipflops & 8) != 0) && zPixel < zbuf[offsetNW]) {
var i = (isCore ? 44 + ((randu >> 25) & 0x07) : (packed >> 25) & 0x3F);
g3d.addPixel (offsetNW, zPixel, shades[i]);
}}}++offsetSE;
--offsetSW;
++offsetNE;
--offsetNW;
++xEast;
--xWest;
flipflops = ~flipflops;
if (isCore) randu = ((randu << 16) + (randu << 1) + randu) & 0x7FFFFFFF;
} while (packed >= 0);
offsetSouthCenter += this.width;
offsetNorthCenter -= this.width;
++ySouth;
--yNorth;
} while (--nLines > 0);
}, "~A,~N,~N,~N,~N");
Clazz.defineMethod (c$, "renderLarge",
function () {
if (this.mat != null) {
if (this.shader.ellipsoidShades == null) this.shader.createEllipsoidShades ();
if (this.octantPoints != null) this.setPlaneDerivatives ();
}this.renderQuadrant (-1, -1);
this.renderQuadrant (-1, 1);
this.renderQuadrant (1, -1);
this.renderQuadrant (1, 1);
});
Clazz.defineMethod (c$, "renderQuadrant",
function (xSign, ySign) {
var radius = Clazz.doubleToInt (this.diameter / 2);
var t = this.x + radius * xSign;
var xStatus = (this.x < 0 ? -1 : this.x < this.width ? 0 : 1) + (t < 0 ? -2 : t < this.width ? 0 : 2);
if (xStatus == -3 || xStatus == 3) return;
t = this.y + radius * ySign;
var yStatus = (this.y < 0 ? -1 : this.y < this.height ? 0 : 1) + (t < 0 ? -2 : t < this.height ? 0 : 2);
if (yStatus == -3 || yStatus == 3) return;
var unclipped = (this.mat == null && xStatus == 0 && yStatus == 0 && this.z - radius >= this.slab && this.z <= this.depth);
if (unclipped) this.renderQuadrantUnclipped (radius, xSign, ySign);
else this.renderQuadrantClipped (radius, xSign, ySign);
}, "~N,~N");
Clazz.defineMethod (c$, "renderQuadrantUnclipped",
function (radius, xSign, ySign) {
var r2 = radius * radius;
var dDivisor = radius * 2 + 1;
var flipflopBeginLine = ((this.x ^ this.y) & 1) == 0;
var lineIncrement = (ySign < 0 ? -this.width : this.width);
var ptLine = this.offsetPbufBeginLine;
for (var i = 0, i2 = 0; i2 <= r2; i2 += i + (++i), ptLine += lineIncrement) {
var offset = ptLine;
var flipflop = (flipflopBeginLine = !flipflopBeginLine);
var s2 = r2 - i2;
var z0 = this.z - radius;
var y8 = Clazz.doubleToInt (((i * ySign + radius) << 8) / dDivisor);
for (var j = 0, j2 = 0; j2 <= s2; j2 += j + (++j), offset += xSign) {
if (this.addAllPixels || (flipflop = !flipflop)) {
if (this.zbuf[offset] <= z0) continue;
var k = Clazz.doubleToInt (Math.sqrt (s2 - j2));
z0 = this.z - k;
if (this.zbuf[offset] <= z0) continue;
var x8 = Clazz.doubleToInt (((j * xSign + radius) << 8) / dDivisor);
this.g3d.addPixel (offset, z0, this.shades[this.shader.sphereShadeIndexes[((y8 << 8) + x8)]]);
}}
}
}, "~N,~N,~N");
Clazz.defineMethod (c$, "renderQuadrantClipped",
function (radius, xSign, ySign) {
var isEllipsoid = (this.mat != null);
var checkOctant = (this.selectedOctant >= 0);
var r2 = radius * radius;
var dDivisor = radius * 2 + 1;
var lineIncrement = (ySign < 0 ? -this.width : this.width);
var ptLine = this.offsetPbufBeginLine;
var randu = (this.x << 16) + (this.y << 1) ^ 0x33333333;
var yCurrent = this.y;
var y8 = 0;
var iShade = 0;
for (var i = 0, i2 = 0; i2 <= r2; i2 += i + (++i), ptLine += lineIncrement, yCurrent += ySign) {
if (yCurrent < 0) {
if (ySign < 0) return;
continue;
}if (yCurrent >= this.height) {
if (ySign > 0) return;
continue;
}var s2 = r2 - (isEllipsoid ? 0 : i2);
var xCurrent = this.x;
if (!isEllipsoid) {
y8 = Clazz.doubleToInt (((i * ySign + radius) << 8) / dDivisor);
}randu = ((randu << 16) + (randu << 1) + randu) & 0x7FFFFFFF;
var iRoot = -1;
var mode = 1;
var offset = ptLine;
for (var j = 0, j2 = 0; j2 <= s2; j2 += j + (++j), offset += xSign, xCurrent += xSign) {
if (xCurrent < 0) {
if (xSign < 0) break;
continue;
}if (xCurrent >= this.width) {
if (xSign > 0) break;
continue;
}if (this.tScreened && (((xCurrent ^ yCurrent) & 1) != 0)) continue;
var zPixel;
if (isEllipsoid) {
if (!J.g3d.SphereRenderer.getQuardricZ (xCurrent, yCurrent, this.coef, this.zroot)) {
if (iRoot >= 0) {
break;
}continue;
}iRoot = (this.z < this.slab ? 1 : 0);
zPixel = Clazz.doubleToInt (this.zroot[iRoot]);
if (zPixel == 0) zPixel = this.z;
mode = 2;
this.z0 = zPixel;
if (checkOctant) {
this.ptTemp.set (xCurrent - this.x, yCurrent - this.y, zPixel - this.z);
this.mat.rotate (this.ptTemp);
var thisOctant = JU.GData.getScreenOctant (this.ptTemp);
if (thisOctant == this.selectedOctant) {
iShade = this.getPlaneShade (xCurrent, yCurrent, this.zroot);
zPixel = Clazz.doubleToInt (this.zroot[0]);
mode = 3;
}var isCore = (this.z < this.slab ? zPixel >= this.slab : zPixel < this.slab);
if (isCore) {
this.z0 = zPixel = this.slab;
mode = 0;
}}if (zPixel < this.slab || zPixel > this.depth || this.zbuf[offset] <= this.z0) continue;
} else {
var zOffset = Clazz.doubleToInt (Math.sqrt (s2 - j2));
zPixel = this.z + (this.z < this.slab ? zOffset : -zOffset);
var isCore = (this.z < this.slab ? zPixel >= this.slab : zPixel < this.slab);
if (isCore) {
zPixel = this.slab;
mode = 0;
}if (zPixel < this.slab || zPixel > this.depth || this.zbuf[offset] <= zPixel) continue;
}switch (mode) {
case 0:
iShade = (44 + ((randu >> 8) & 0x07));
randu = ((randu << 16) + (randu << 1) + randu) & 0x7FFFFFFF;
mode = 1;
break;
case 2:
iShade = this.shader.getEllipsoidShade (xCurrent, yCurrent, this.zroot[iRoot], radius, this.mDeriv);
break;
case 3:
this.g3d.clearPixel (offset, this.z0);
break;
default:
var x8 = Clazz.doubleToInt (((j * xSign + radius) << 8) / dDivisor);
iShade = this.shader.sphereShadeIndexes[(y8 << 8) + x8];
break;
}
this.g3d.addPixel (offset, zPixel, this.shades[iShade]);
}
randu = ((randu + xCurrent + yCurrent) | 1) & 0x7FFFFFFF;
}
}, "~N,~N,~N");
c$.getQuardricZ = Clazz.defineMethod (c$, "getQuardricZ",
function (x, y, coef, zroot) {
var b_2a = (coef[4] * x + coef[5] * y + coef[8]) / coef[2] / 2;
var c_a = (coef[0] * x * x + coef[1] * y * y + coef[3] * x * y + coef[6] * x + coef[7] * y - 1) / coef[2];
var f = b_2a * b_2a - c_a;
if (f < 0) return false;
f = Math.sqrt (f);
zroot[0] = (-b_2a - f);
zroot[1] = (-b_2a + f);
return true;
}, "~N,~N,~A,~A");
Clazz.defineMethod (c$, "setPlaneDerivatives",
function () {
this.planeShade = -1;
for (var i = 0; i < 3; i++) {
var dx = this.dxyz[i][0] = this.octantPoints[i].x - this.x;
var dy = this.dxyz[i][1] = this.octantPoints[i].y - this.y;
var dz = this.dxyz[i][2] = this.octantPoints[i].z - this.z;
this.planeShades[i] = this.shader.getShadeIndex (dx, dy, -dz);
if (dx == 0 && dy == 0) {
this.planeShade = this.planeShades[i];
return;
}}
});
Clazz.defineMethod (c$, "getPlaneShade",
function (xCurrent, yCurrent, zroot) {
if (this.planeShade >= 0) return this.planeShade;
var iMin = 3;
var dz;
var zMin = 3.4028235E38;
for (var i = 0; i < 3; i++) {
if ((dz = this.dxyz[i][2]) == 0) continue;
var ptz = this.z + (-this.dxyz[i][0] * (xCurrent - this.x) - this.dxyz[i][1] * (yCurrent - this.y)) / dz;
if (ptz < zMin) {
zMin = ptz;
iMin = i;
}}
if (iMin == 3) {
iMin = 0;
zMin = this.z;
}zroot[0] = zMin;
return this.planeShades[iMin];
}, "~N,~N,~A");
Clazz.defineStatics (c$,
"maxOddSizeSphere", 49,
"maxSphereDiameter", 1000,
"maxSphereDiameter2", 2000,
"SHADE_SLAB_CLIPPED", 47);
});