NGL@1.0.0-beta.7 Home Manual Reference Source Gallery

src/surface/edt-surface.js

  1. /**
  2. * @file EDT Surface
  3. * @author Alexander Rose <alexander.rose@weirdbyte.de>
  4. * @private
  5. */
  6.  
  7. import { VolumeSurface } from './volume.js'
  8. import Grid from '../geometry/grid.js'
  9. import { computeBoundingBox } from '../math/vector-utils.js'
  10. import { getRadiusDict, getSurfaceGrid } from './surface-utils.js'
  11.  
  12. function EDTSurface (coordList, radiusList, indexList) {
  13. // based on D. Xu, Y. Zhang (2009) Generating Triangulated Macromolecular
  14. // Surfaces by Euclidean Distance Transform. PLoS ONE 4(12): e8140.
  15. //
  16. // Permission to use, copy, modify, and distribute this program for
  17. // any purpose, with or without fee, is hereby granted, provided that
  18. // the notices on the head, the reference information, and this
  19. // copyright notice appear in all copies or substantial portions of
  20. // the Software. It is provided "as is" without express or implied
  21. // warranty.
  22. //
  23. // ported to JavaScript by biochem_fan (http://webglmol.sourceforge.jp/)
  24. // refactored by dkoes (https://github.com/dkoes)
  25. //
  26. // adapted to NGL by Alexander Rose
  27.  
  28. var radiusDict = getRadiusDict(radiusList)
  29. var bbox = computeBoundingBox(coordList)
  30. if (coordList.length === 0) {
  31. bbox[ 0 ].set([ 0, 0, 0 ])
  32. bbox[ 1 ].set([ 0, 0, 0 ])
  33. }
  34. var min = bbox[ 0 ]
  35. var max = bbox[ 1 ]
  36.  
  37. var probeRadius, scaleFactor, cutoff
  38. var pLength, pWidth, pHeight
  39. var matrix, ptran
  40. var depty, widxz
  41. var cutRadius
  42. var setAtomID
  43. var vpBits, vpDistance, vpAtomID
  44.  
  45. function init (btype, _probeRadius, _scaleFactor, _cutoff, _setAtomID) {
  46. probeRadius = _probeRadius || 1.4
  47. scaleFactor = _scaleFactor || 2.0
  48. setAtomID = _setAtomID || true
  49.  
  50. var maxRadius = 0
  51. for (var radius in radiusDict) {
  52. maxRadius = Math.max(maxRadius, radius)
  53. }
  54.  
  55. var grid = getSurfaceGrid(
  56. min, max, maxRadius, scaleFactor, btype ? probeRadius : 0
  57. )
  58.  
  59. pLength = grid.dim[0]
  60. pWidth = grid.dim[1]
  61. pHeight = grid.dim[2]
  62.  
  63. matrix = grid.matrix
  64. ptran = grid.tran
  65. scaleFactor = grid.scaleFactor
  66.  
  67. // boundingatom caches
  68. depty = {}
  69. widxz = {}
  70. boundingatom(btype)
  71.  
  72. cutRadius = probeRadius * scaleFactor
  73.  
  74. if (_cutoff) {
  75. cutoff = _cutoff
  76. } else {
  77. // cutoff = Math.max( 0.1, -1.2 + scaleFactor * probeRadius );
  78. cutoff = probeRadius / scaleFactor
  79. }
  80.  
  81. vpBits = new Uint8Array(pLength * pWidth * pHeight)
  82. if (btype) {
  83. vpDistance = new Float64Array(pLength * pWidth * pHeight)
  84. }
  85. if (setAtomID) {
  86. vpAtomID = new Int32Array(pLength * pWidth * pHeight)
  87. }
  88. }
  89.  
  90. // constants for vpBits bitmasks
  91. var INOUT = 1
  92. var ISDONE = 2
  93. var ISBOUND = 4
  94.  
  95. var nb = [
  96. new Int32Array([ 1, 0, 0 ]), new Int32Array([ -1, 0, 0 ]),
  97. new Int32Array([ 0, 1, 0 ]), new Int32Array([ 0, -1, 0 ]),
  98. new Int32Array([ 0, 0, 1 ]), new Int32Array([ 0, 0, -1 ]),
  99. new Int32Array([ 1, 1, 0 ]), new Int32Array([ 1, -1, 0 ]),
  100. new Int32Array([ -1, 1, 0 ]), new Int32Array([ -1, -1, 0 ]),
  101. new Int32Array([ 1, 0, 1 ]), new Int32Array([ 1, 0, -1 ]),
  102. new Int32Array([ -1, 0, 1 ]), new Int32Array([ -1, 0, -1 ]),
  103. new Int32Array([ 0, 1, 1 ]), new Int32Array([ 0, 1, -1 ]),
  104. new Int32Array([ 0, -1, 1 ]), new Int32Array([ 0, -1, -1 ]),
  105. new Int32Array([ 1, 1, 1 ]), new Int32Array([ 1, 1, -1 ]),
  106. new Int32Array([ 1, -1, 1 ]), new Int32Array([ -1, 1, 1 ]),
  107. new Int32Array([ 1, -1, -1 ]), new Int32Array([ -1, -1, 1 ]),
  108. new Int32Array([ -1, 1, -1 ]), new Int32Array([ -1, -1, -1 ])
  109. ]
  110.  
  111. //
  112.  
  113. this.getVolume = function (type, probeRadius, scaleFactor, cutoff, setAtomID) {
  114. console.time('EDTSurface.getVolume')
  115.  
  116. var btype = type !== 'vws'
  117.  
  118. init(btype, probeRadius, scaleFactor, cutoff, setAtomID)
  119.  
  120. fillvoxels(btype)
  121. buildboundary()
  122.  
  123. if (type === 'ms' || type === 'ses') {
  124. fastdistancemap()
  125. }
  126.  
  127. if (type === 'ses') {
  128. boundingatom(false)
  129. fillvoxelswaals()
  130. }
  131.  
  132. marchingcubeinit(type)
  133.  
  134. // set atomindex in the volume data
  135. for (var i = 0, il = vpAtomID.length; i < il; ++i) {
  136. vpAtomID[ i ] = indexList[ vpAtomID[ i ] ]
  137. }
  138.  
  139. console.timeEnd('EDTSurface.getVolume')
  140.  
  141. return {
  142. data: vpBits,
  143. nx: pHeight,
  144. ny: pWidth,
  145. nz: pLength,
  146. atomindex: vpAtomID
  147. }
  148. }
  149.  
  150. this.getSurface = function (type, probeRadius, scaleFactor, cutoff, setAtomID, smooth, contour) {
  151. var vd = this.getVolume(
  152. type, probeRadius, scaleFactor, cutoff, setAtomID
  153. )
  154.  
  155. var volsurf = new VolumeSurface(
  156. vd.data, vd.nx, vd.ny, vd.nz, vd.atomindex
  157. )
  158.  
  159. return volsurf.getSurface(1, smooth, undefined, matrix, contour)
  160. }
  161.  
  162. function boundingatom (btype) {
  163. var r
  164. var j
  165. var k
  166. var txz
  167. var tdept
  168. var sradius
  169. var tradius
  170. var widxzR
  171. var deptyName
  172. var indx
  173.  
  174. for (var name in radiusDict) {
  175. r = radiusDict[ name ]
  176.  
  177. if (depty[ name ]) continue
  178.  
  179. if (!btype) {
  180. tradius = r * scaleFactor + 0.5
  181. } else {
  182. tradius = (r + probeRadius) * scaleFactor + 0.5
  183. }
  184.  
  185. sradius = tradius * tradius
  186. widxzR = Math.floor(tradius) + 1
  187. deptyName = new Int32Array(widxzR * widxzR)
  188. indx = 0
  189.  
  190. for (j = 0; j < widxzR; ++j) {
  191. for (k = 0; k < widxzR; ++k) {
  192. txz = j * j + k * k
  193.  
  194. if (txz > sradius) {
  195. deptyName[ indx ] = -1
  196. } else {
  197. tdept = Math.sqrt(sradius - txz)
  198. deptyName[ indx ] = Math.floor(tdept)
  199. }
  200.  
  201. ++indx
  202. }
  203. }
  204.  
  205. widxz[ name ] = widxzR
  206. depty[ name ] = deptyName
  207. }
  208. }
  209.  
  210. function fillatom (idx) {
  211. var ci = idx * 3
  212. var ri = idx
  213.  
  214. var cx, cy, cz, ox, oy, oz, mi, mj, mk, i, j, k, si, sj, sk
  215. var ii, jj, kk
  216.  
  217. cx = Math.floor(0.5 + scaleFactor * (coordList[ ci ] + ptran[0]))
  218. cy = Math.floor(0.5 + scaleFactor * (coordList[ ci + 1 ] + ptran[1]))
  219. cz = Math.floor(0.5 + scaleFactor * (coordList[ ci + 2 ] + ptran[2]))
  220.  
  221. var at = radiusList[ ri ]
  222. var deptyAt = depty[ at ]
  223. var nind = 0
  224. var pWH = pWidth * pHeight
  225. var n = widxz[ at ]
  226.  
  227. var deptyAtNind
  228.  
  229. for (i = 0; i < n; ++i) {
  230. for (j = 0; j < n; ++j) {
  231. deptyAtNind = deptyAt[ nind ]
  232.  
  233. if (deptyAtNind !== -1) {
  234. for (ii = -1; ii < 2; ++ii) {
  235. for (jj = -1; jj < 2; ++jj) {
  236. for (kk = -1; kk < 2; ++kk) {
  237. if (ii !== 0 && jj !== 0 && kk !== 0) {
  238. mi = ii * i
  239. mk = kk * j
  240.  
  241. for (k = 0; k <= deptyAtNind; ++k) {
  242. mj = k * jj
  243. si = cx + mi
  244. sj = cy + mj
  245. sk = cz + mk
  246.  
  247. if (si < 0 || sj < 0 || sk < 0 ||
  248. si >= pLength || sj >= pWidth || sk >= pHeight
  249. ) {
  250. continue
  251. }
  252.  
  253. var index = si * pWH + sj * pHeight + sk
  254.  
  255. if (!setAtomID) {
  256. vpBits[ index ] |= INOUT
  257. } else {
  258. if (!(vpBits[ index ] & INOUT)) {
  259. vpBits[ index ] |= INOUT
  260. vpAtomID[ index ] = idx
  261. } else if (vpBits[ index ] & INOUT) {
  262. var ci2 = vpAtomID[ index ]
  263.  
  264. if (ci2 !== ci) {
  265. ox = cx + mi - Math.floor(0.5 + scaleFactor * (coordList[ci2] + ptran[0]))
  266. oy = cy + mj - Math.floor(0.5 + scaleFactor * (coordList[ci2 + 1] + ptran[1]))
  267. oz = cz + mk - Math.floor(0.5 + scaleFactor * (coordList[ci2 + 2] + ptran[2]))
  268.  
  269. if (mi * mi + mj * mj + mk * mk < ox * ox + oy * oy + oz * oz) {
  270. vpAtomID[ index ] = idx
  271. }
  272. }
  273. }
  274. }
  275. }// k
  276. }// if
  277. }// kk
  278. }// jj
  279. }// ii
  280. }// if
  281.  
  282. nind++
  283. }// j
  284. }// i
  285. }
  286.  
  287. function fillvoxels (btype) {
  288. console.time('EDTSurface fillvoxels')
  289.  
  290. var i, il
  291.  
  292. for (i = 0, il = vpBits.length; i < il; ++i) {
  293. vpBits[ i ] = 0
  294. if (btype) vpDistance[ i ] = -1.0
  295. if (setAtomID) vpAtomID[ i ] = -1
  296. }
  297.  
  298. for (i = 0, il = coordList.length / 3; i < il; ++i) {
  299. fillatom(i)
  300. }
  301.  
  302. for (i = 0, il = vpBits.length; i < il; ++i) {
  303. if (vpBits[ i ] & INOUT) {
  304. vpBits[ i ] |= ISDONE
  305. }
  306. }
  307.  
  308. console.timeEnd('EDTSurface fillvoxels')
  309. }
  310.  
  311. function fillAtomWaals (idx) {
  312. var ci = idx * 3
  313. var ri = idx
  314.  
  315. var cx
  316. var cy
  317. var cz
  318. var ox
  319. var oy
  320. var oz
  321. var nind = 0
  322.  
  323. var mi
  324. var mj
  325. var mk
  326. var si
  327. var sj
  328. var sk
  329. var i
  330. var j
  331. var k
  332. var ii
  333. var jj
  334. var kk
  335. var n
  336.  
  337. cx = Math.floor(0.5 + scaleFactor * (coordList[ ci ] + ptran[0]))
  338. cy = Math.floor(0.5 + scaleFactor * (coordList[ ci + 1 ] + ptran[1]))
  339. cz = Math.floor(0.5 + scaleFactor * (coordList[ ci + 2 ] + ptran[2]))
  340.  
  341. var at = radiusList[ ri ]
  342. var pWH = pWidth * pHeight
  343.  
  344. for (i = 0, n = widxz[at]; i < n; ++i) {
  345. for (j = 0; j < n; ++j) {
  346. if (depty[ at ][ nind ] !== -1) {
  347. for (ii = -1; ii < 2; ++ii) {
  348. for (jj = -1; jj < 2; ++jj) {
  349. for (kk = -1; kk < 2; ++kk) {
  350. if (ii !== 0 && jj !== 0 && kk !== 0) {
  351. mi = ii * i
  352. mk = kk * j
  353.  
  354. for (k = 0; k <= depty[ at ][ nind ]; ++k) {
  355. mj = k * jj
  356. si = cx + mi
  357. sj = cy + mj
  358. sk = cz + mk
  359.  
  360. if (si < 0 || sj < 0 || sk < 0 ||
  361. si >= pLength || sj >= pWidth || sk >= pHeight
  362. ) {
  363. continue
  364. }
  365.  
  366. var index = si * pWH + sj * pHeight + sk
  367.  
  368. if (!(vpBits[ index ] & ISDONE)) {
  369. vpBits[ index ] |= ISDONE
  370. if (setAtomID) vpAtomID[ index ] = idx
  371. } else if (setAtomID) {
  372. var ci2 = vpAtomID[ index ]
  373.  
  374. ox = Math.floor(0.5 + scaleFactor * (coordList[ ci2 ] + ptran[0]))
  375. oy = Math.floor(0.5 + scaleFactor * (coordList[ ci2 + 1 ] + ptran[1]))
  376. oz = Math.floor(0.5 + scaleFactor * (coordList[ ci2 + 2 ] + ptran[2]))
  377.  
  378. if (mi * mi + mj * mj + mk * mk < ox * ox + oy * oy + oz * oz) {
  379. vpAtomID[ index ] = idx
  380. }
  381. }
  382. }// k
  383. }// if
  384. }// kk
  385. }// jj
  386. }// ii
  387. }// if
  388.  
  389. nind++
  390. }// j
  391. }// i
  392. }
  393.  
  394. function fillvoxelswaals () {
  395. var i, il
  396.  
  397. for (i = 0, il = vpBits.length; i < il; ++i) {
  398. vpBits[ i ] &= ~ISDONE // not isdone
  399. }
  400.  
  401. for (i = 0, il = coordList.length / 3; i < il; ++i) {
  402. fillAtomWaals(i)
  403. }
  404. }
  405.  
  406. function buildboundary () {
  407. var i, j, k
  408. var pWH = pWidth * pHeight
  409.  
  410. for (i = 0; i < pLength; ++i) {
  411. for (j = 0; j < pHeight; ++j) {
  412. for (k = 0; k < pWidth; ++k) {
  413. var index = i * pWH + k * pHeight + j
  414.  
  415. if (vpBits[ index ] & INOUT) {
  416. // var flagbound = false;
  417. var ii = 0
  418.  
  419. // while( !flagbound && ii < 26 ){
  420. while (ii < 26) {
  421. var ti = i + nb[ ii ][ 0 ]
  422. var tj = j + nb[ ii ][ 2 ]
  423. var tk = k + nb[ ii ][ 1 ]
  424.  
  425. if (ti > -1 && ti < pLength &&
  426. tk > -1 && tk < pWidth &&
  427. tj > -1 && tj < pHeight &&
  428. !(vpBits[ ti * pWH + tk * pHeight + tj ] & INOUT)
  429. ) {
  430. vpBits[ index ] |= ISBOUND
  431. // flagbound = true;
  432. break
  433. } else {
  434. ii++
  435. }
  436. }
  437. }
  438. } // k
  439. } // j
  440. } // i
  441. }
  442.  
  443. function fastdistancemap () {
  444. console.time('EDTSurface fastdistancemap')
  445.  
  446. var i, j, k, n
  447.  
  448. var boundPoint = new Grid(
  449. pLength, pWidth, pHeight, Uint16Array, 3
  450. )
  451. var pWH = pWidth * pHeight
  452. var cutRSq = cutRadius * cutRadius
  453.  
  454. var totalsurfacevox = 0
  455. // var totalinnervox = 0;
  456.  
  457. var index
  458.  
  459. for (i = 0; i < pLength; ++i) {
  460. for (j = 0; j < pWidth; ++j) {
  461. for (k = 0; k < pHeight; ++k) {
  462. index = i * pWH + j * pHeight + k
  463.  
  464. vpBits[ index ] &= ~ISDONE
  465.  
  466. if (vpBits[ index ] & INOUT) {
  467. if (vpBits[ index ] & ISBOUND) {
  468. boundPoint.set(
  469. i, j, k,
  470. i, j, k
  471. )
  472.  
  473. vpDistance[ index ] = 0
  474. vpBits[ index ] |= ISDONE
  475.  
  476. totalsurfacevox += 1
  477. }/* else{
  478.  
  479. totalinnervox += 1;
  480.  
  481. } */
  482. }
  483. }
  484. }
  485. }
  486.  
  487. var inarray = new Int32Array(3 * totalsurfacevox)
  488. var positin = 0
  489. var outarray = new Int32Array(3 * totalsurfacevox)
  490. var positout = 0
  491.  
  492. for (i = 0; i < pLength; ++i) {
  493. for (j = 0; j < pWidth; ++j) {
  494. for (k = 0; k < pHeight; ++k) {
  495. index = i * pWH + j * pHeight + k
  496.  
  497. if (vpBits[ index ] & ISBOUND) {
  498. inarray[ positin ] = i
  499. inarray[ positin + 1 ] = j
  500. inarray[ positin + 2 ] = k
  501. positin += 3
  502.  
  503. vpBits[ index ] &= ~ISBOUND
  504. }
  505. }
  506. }
  507. }
  508.  
  509. do {
  510. positout = fastoneshell(inarray, boundPoint, positin, outarray)
  511. positin = 0
  512.  
  513. for (i = 0, n = positout; i < n; i += 3) {
  514. index = pWH * outarray[ i ] + pHeight * outarray[ i + 1 ] + outarray[ i + 2 ]
  515. vpBits[ index ] &= ~ISBOUND
  516.  
  517. if (vpDistance[ index ] <= 1.0404 * cutRSq) {
  518. // if( vpDistance[ index ] <= 1.02 * cutRadius ){
  519.  
  520. inarray[ positin ] = outarray[ i ]
  521. inarray[ positin + 1 ] = outarray[ i + 1 ]
  522. inarray[ positin + 2 ] = outarray[ i + 2 ]
  523. positin += 3
  524. }
  525. }
  526. } while (positin > 0)
  527.  
  528. // var cutsf = Math.max( 0, scaleFactor - 0.5 );
  529. // cutoff = cutRadius - 0.5 / ( 0.1 + cutsf );
  530. var cutoffSq = cutoff * cutoff
  531.  
  532. var index2
  533. var bp = new Uint16Array(3)
  534.  
  535. for (i = 0; i < pLength; ++i) {
  536. for (j = 0; j < pWidth; ++j) {
  537. for (k = 0; k < pHeight; ++k) {
  538. index = i * pWH + j * pHeight + k
  539. vpBits[ index ] &= ~ISBOUND
  540.  
  541. // ses solid
  542.  
  543. if (vpBits[ index ] & INOUT) {
  544. if (!(vpBits[ index ] & ISDONE) ||
  545. ((vpBits[ index ] & ISDONE) && vpDistance[ index ] >= cutoffSq)
  546. ) {
  547. vpBits[ index ] |= ISBOUND
  548.  
  549. if (setAtomID && (vpBits[ index ] & ISDONE)) {
  550. boundPoint.toArray(i, j, k, bp)
  551. index2 = bp[ 0 ] * pWH + bp[ 1 ] * pHeight + bp[ 2 ]
  552.  
  553. vpAtomID[ index ] = vpAtomID[ index2 ]
  554. }
  555. }
  556. }
  557. }
  558. }
  559. }
  560.  
  561. console.timeEnd('EDTSurface fastdistancemap')
  562. }
  563.  
  564. function fastoneshell (inarray, boundPoint, positin, outarray) {
  565. // *allocout,voxel2
  566. // ***boundPoint, int*
  567. // outnum, int *elimi)
  568. var tx, ty, tz
  569. var dx, dy, dz
  570. var i, j, n
  571. var square
  572. var index
  573. var nbj
  574. var bp = new Uint16Array(3)
  575. var positout = 0
  576.  
  577. if (positin === 0) {
  578. return positout
  579. }
  580.  
  581. var tnvix = -1
  582. var tnviy = -1
  583. var tnviz = -1
  584.  
  585. var pWH = pWidth * pHeight
  586.  
  587. for (i = 0, n = positin; i < n; i += 3) {
  588. tx = inarray[ i ]
  589. ty = inarray[ i + 1 ]
  590. tz = inarray[ i + 2 ]
  591. boundPoint.toArray(tx, ty, tz, bp)
  592.  
  593. for (j = 0; j < 6; ++j) {
  594. nbj = nb[ j ]
  595. tnvix = tx + nbj[ 0 ]
  596. tnviy = ty + nbj[ 1 ]
  597. tnviz = tz + nbj[ 2 ]
  598.  
  599. if (tnvix < pLength && tnvix > -1 &&
  600. tnviy < pWidth && tnviy > -1 &&
  601. tnviz < pHeight && tnviz > -1
  602. ) {
  603. index = tnvix * pWH + pHeight * tnviy + tnviz
  604.  
  605. if ((vpBits[ index ] & INOUT) && !(vpBits[ index ] & ISDONE)) {
  606. boundPoint.fromArray(tnvix, tnviy, tnviz, bp)
  607. dx = tnvix - bp[ 0 ]
  608. dy = tnviy - bp[ 1 ]
  609. dz = tnviz - bp[ 2 ]
  610. square = dx * dx + dy * dy + dz * dz
  611. // square = Math.sqrt( square );
  612.  
  613. vpDistance[ index ] = square
  614. vpBits[ index ] |= ISDONE
  615. vpBits[ index ] |= ISBOUND
  616.  
  617. outarray[ positout ] = tnvix
  618. outarray[ positout + 1 ] = tnviy
  619. outarray[ positout + 2 ] = tnviz
  620. positout += 3
  621. } else if ((vpBits[ index ] & INOUT) && (vpBits[ index ] & ISDONE)) {
  622. dx = tnvix - bp[ 0 ]
  623. dy = tnviy - bp[ 1 ]
  624. dz = tnviz - bp[ 2 ]
  625. square = dx * dx + dy * dy + dz * dz
  626. // square = Math.sqrt( square );
  627.  
  628. if (square < vpDistance[ index ]) {
  629. boundPoint.fromArray(tnvix, tnviy, tnviz, bp)
  630. vpDistance[ index ] = square
  631.  
  632. if (!(vpBits[ index ] & ISBOUND)) {
  633. vpBits[ index ] |= ISBOUND
  634.  
  635. outarray[ positout ] = tnvix
  636. outarray[ positout + 1 ] = tnviy
  637. outarray[ positout + 2 ] = tnviz
  638. positout += 3
  639. }
  640. }
  641. }
  642. }
  643. }
  644. }
  645.  
  646. for (i = 0, n = positin; i < n; i += 3) {
  647. tx = inarray[ i ]
  648. ty = inarray[ i + 1 ]
  649. tz = inarray[ i + 2 ]
  650. boundPoint.toArray(tx, ty, tz, bp)
  651.  
  652. for (j = 6; j < 18; j++) {
  653. nbj = nb[ j ]
  654. tnvix = tx + nbj[ 0 ]
  655. tnviy = ty + nbj[ 1 ]
  656. tnviz = tz + nbj[ 2 ]
  657.  
  658. if (tnvix < pLength && tnvix > -1 &&
  659. tnviy < pWidth && tnviy > -1 &&
  660. tnviz < pHeight && tnviz > -1
  661. ) {
  662. index = tnvix * pWH + pHeight * tnviy + tnviz
  663.  
  664. if ((vpBits[index] & INOUT) && !(vpBits[index] & ISDONE)) {
  665. boundPoint.fromArray(tnvix, tnviy, tnviz, bp)
  666. dx = tnvix - bp[ 0 ]
  667. dy = tnviy - bp[ 1 ]
  668. dz = tnviz - bp[ 2 ]
  669. square = dx * dx + dy * dy + dz * dz
  670. // square = Math.sqrt( square );
  671.  
  672. vpDistance[index] = square
  673. vpBits[index] |= ISDONE
  674. vpBits[index] |= ISBOUND
  675.  
  676. outarray[ positout ] = tnvix
  677. outarray[ positout + 1 ] = tnviy
  678. outarray[ positout + 2 ] = tnviz
  679. positout += 3
  680. } else if ((vpBits[index] & INOUT) && (vpBits[index] & ISDONE)) {
  681. dx = tnvix - bp[ 0 ]
  682. dy = tnviy - bp[ 1 ]
  683. dz = tnviz - bp[ 2 ]
  684. square = dx * dx + dy * dy + dz * dz
  685. // square = Math.sqrt( square );
  686.  
  687. if (square < vpDistance[index]) {
  688. boundPoint.fromArray(tnvix, tnviy, tnviz, bp)
  689. vpDistance[index] = square
  690.  
  691. if (!(vpBits[index] & ISBOUND)) {
  692. vpBits[index] |= ISBOUND
  693.  
  694. outarray[ positout ] = tnvix
  695. outarray[ positout + 1 ] = tnviy
  696. outarray[ positout + 2 ] = tnviz
  697. positout += 3
  698. }
  699. }
  700. }
  701. }
  702. }
  703. }
  704.  
  705. for (i = 0, n = positin; i < n; i += 3) {
  706. tx = inarray[ i ]
  707. ty = inarray[ i + 1 ]
  708. tz = inarray[ i + 2 ]
  709. boundPoint.toArray(tx, ty, tz, bp)
  710.  
  711. for (j = 18; j < 26; j++) {
  712. nbj = nb[ j ]
  713. tnvix = tx + nbj[ 0 ]
  714. tnviy = ty + nbj[ 1 ]
  715. tnviz = tz + nbj[ 2 ]
  716.  
  717. if (tnvix < pLength && tnvix > -1 &&
  718. tnviy < pWidth && tnviy > -1 &&
  719. tnviz < pHeight && tnviz > -1
  720. ) {
  721. index = tnvix * pWH + pHeight * tnviy + tnviz
  722.  
  723. if ((vpBits[index] & INOUT) && !(vpBits[index] & ISDONE)) {
  724. boundPoint.fromArray(tnvix, tnviy, tnviz, bp)
  725. dx = tnvix - bp[ 0 ]
  726. dy = tnviy - bp[ 1 ]
  727. dz = tnviz - bp[ 2 ]
  728. square = dx * dx + dy * dy + dz * dz
  729. // square = Math.sqrt( square );
  730.  
  731. vpDistance[index] = square
  732. vpBits[index] |= ISDONE
  733. vpBits[index] |= ISBOUND
  734.  
  735. outarray[ positout ] = tnvix
  736. outarray[ positout + 1 ] = tnviy
  737. outarray[ positout + 2 ] = tnviz
  738. positout += 3
  739. } else if ((vpBits[index] & INOUT) && (vpBits[index] & ISDONE)) {
  740. dx = tnvix - bp[ 0 ]
  741. dy = tnviy - bp[ 1 ]
  742. dz = tnviz - bp[ 2 ]
  743. square = dx * dx + dy * dy + dz * dz
  744. // square = Math.sqrt( square );
  745.  
  746. if (square < vpDistance[index]) {
  747. boundPoint.fromArray(tnvix, tnviy, tnviz, bp)
  748. vpDistance[index] = square
  749.  
  750. if (!(vpBits[index] & ISBOUND)) {
  751. vpBits[index] |= ISBOUND
  752.  
  753. outarray[ positout ] = tnvix
  754. outarray[ positout + 1 ] = tnviy
  755. outarray[ positout + 2 ] = tnviz
  756. positout += 3
  757. }
  758. }
  759. }
  760. }
  761. }
  762. }
  763.  
  764. return positout
  765. }
  766.  
  767. function marchingcubeinit (stype) {
  768. var i
  769. var n = vpBits.length
  770.  
  771. if (stype === 'vws') {
  772. for (i = 0; i < n; ++i) {
  773. vpBits[ i ] &= ~ISBOUND
  774. vpBits[ i ] = (vpBits[ i ] & ISDONE) ? 1 : 0
  775. }
  776. } else if (stype === 'ms') { // ses without vdw => ms
  777. for (i = 0; i < n; ++i) {
  778. vpBits[ i ] &= ~ISDONE
  779. if (vpBits[ i ] & ISBOUND) {
  780. vpBits[ i ] |= ISDONE
  781. }
  782. vpBits[ i ] &= ~ISBOUND
  783. vpBits[ i ] = (vpBits[ i ] & ISDONE) ? 1 : 0
  784. }
  785. } else if (stype === 'ses') {
  786. for (i = 0; i < n; ++i) {
  787. if ((vpBits[ i ] & ISBOUND) && (vpBits[ i ] & ISDONE)) {
  788. vpBits[ i ] &= ~ISBOUND
  789. } else if ((vpBits[ i ] & ISBOUND) && !(vpBits[ i ] & ISDONE)) {
  790. vpBits[ i ] |= ISDONE
  791. }
  792. vpBits[ i ] = (vpBits[ i ] & ISDONE) ? 1 : 0
  793. }
  794. } else if (stype === 'sas') {
  795. for (i = 0; i < n; ++i) {
  796. vpBits[ i ] &= ~ISBOUND
  797. vpBits[ i ] = (vpBits[ i ] & ISDONE) ? 1 : 0
  798. }
  799. }
  800. }
  801. }
  802. EDTSurface.__deps = [
  803. getSurfaceGrid, getRadiusDict, VolumeSurface, computeBoundingBox, Grid
  804. ]
  805.  
  806. export default EDTSurface