UNPKG

biojs-vis-pdbviewer

Version:

A BioJS 2.0 component to view protein structures

463 lines (462 loc) 16.7 kB
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); });