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

src/surface/surface-utils.js

  1. /**
  2. * @file Surface Utils
  3. * @author Alexander Rose <alexander.rose@weirdbyte.de>
  4. * @private
  5. */
  6.  
  7. import { degToRad } from '../math/math-utils.js'
  8. import {
  9. m4new, m4multiply, m4makeTranslation, m4makeScale, m4makeRotationY
  10. } from '../math/matrix-utils.js'
  11. import {
  12. v3addScalar, v3subScalar, v3divideScalar, v3multiplyScalar,
  13. v3floor, v3ceil, v3sub, v3negate,
  14. v3cross, v3fromArray, normalizeVector3array
  15. } from '../math/vector-utils.js'
  16.  
  17. function laplacianSmooth (verts, faces, numiter, inflate) {
  18. // based on D. Xu, Y. Zhang (2009) Generating Triangulated Macromolecular
  19. // Surfaces by Euclidean Distance Transform. PLoS ONE 4(12): e8140.
  20. //
  21. // Permission to use, copy, modify, and distribute this program for
  22. // any purpose, with or without fee, is hereby granted, provided that
  23. // the notices on the head, the reference information, and this
  24. // copyright notice appear in all copies or substantial portions of
  25. // the Software. It is provided "as is" without express or implied
  26. // warranty.
  27. //
  28. // ported to JavaScript and adapted to NGL by Alexander Rose
  29.  
  30. numiter = numiter || 1
  31. inflate = inflate || true
  32.  
  33. var nv = verts.length / 3
  34. var nf = faces.length / 3
  35. var norms
  36.  
  37. if (inflate) {
  38. norms = new Float32Array(nv * 3)
  39. }
  40.  
  41. var tps = new Float32Array(nv * 3)
  42.  
  43. var i
  44. var ndeg = 20
  45. var vertdeg = new Array(ndeg)
  46.  
  47. for (i = 0; i < ndeg; ++i) {
  48. vertdeg[ i ] = new Uint32Array(nv)
  49. }
  50.  
  51. for (i = 0; i < nv; ++i) {
  52. vertdeg[ 0 ][ i ] = 0
  53. }
  54.  
  55. var j, jl
  56. var flagvert
  57.  
  58. // for each face
  59.  
  60. for (i = 0; i < nf; ++i) {
  61. var ao = i * 3
  62. var bo = i * 3 + 1
  63. var co = i * 3 + 2
  64.  
  65. // vertex a
  66.  
  67. flagvert = true
  68. for (j = 0, jl = vertdeg[ 0 ][ faces[ao] ]; j < jl; ++j) {
  69. if (faces[ bo ] === vertdeg[ j + 1 ][ faces[ ao ] ]) {
  70. flagvert = false
  71. break
  72. }
  73. }
  74. if (flagvert) {
  75. vertdeg[ 0 ][ faces[ ao ] ]++
  76. vertdeg[ vertdeg[ 0 ][ faces[ ao ] ] ][ faces[ ao ] ] = faces[ bo ]
  77. }
  78.  
  79. flagvert = true
  80. for (j = 0, jl = vertdeg[ 0 ][ faces[ ao ] ]; j < jl; ++j) {
  81. if (faces[ co ] === vertdeg[ j + 1 ][ faces[ ao ] ]) {
  82. flagvert = false
  83. break
  84. }
  85. }
  86. if (flagvert) {
  87. vertdeg[ 0 ][ faces[ ao ] ]++
  88. vertdeg[ vertdeg[ 0 ][ faces[ ao ] ] ][ faces[ ao ] ] = faces[ co ]
  89. }
  90.  
  91. // vertex b
  92.  
  93. flagvert = true
  94. for (j = 0, jl = vertdeg[ 0 ][ faces[ bo ] ]; j < jl; ++j) {
  95. if (faces[ ao ] === vertdeg[ j + 1 ][ faces[ bo ] ]) {
  96. flagvert = false
  97. break
  98. }
  99. }
  100. if (flagvert) {
  101. vertdeg[ 0 ][ faces[ bo ] ]++
  102. vertdeg[ vertdeg[ 0 ][ faces[ bo ] ] ][ faces[ bo ] ] = faces[ ao ]
  103. }
  104.  
  105. flagvert = true
  106. for (j = 0, jl = vertdeg[ 0 ][ faces[ bo ] ]; j < jl; ++j) {
  107. if (faces[ co ] === vertdeg[ j + 1 ][ faces[ bo ] ]) {
  108. flagvert = false
  109. break
  110. }
  111. }
  112. if (flagvert) {
  113. vertdeg[ 0 ][ faces[ bo ] ]++
  114. vertdeg[ vertdeg[ 0 ][ faces[ bo ] ] ][ faces[ bo ] ] = faces[ co ]
  115. }
  116.  
  117. // vertex c
  118.  
  119. flagvert = true
  120. for (j = 0; j < vertdeg[ 0 ][ faces[ co ] ]; ++j) {
  121. if (faces[ ao ] === vertdeg[ j + 1 ][ faces[ co ] ]) {
  122. flagvert = false
  123. break
  124. }
  125. }
  126. if (flagvert) {
  127. vertdeg[ 0 ][ faces[ co ] ]++
  128. vertdeg[ vertdeg[ 0 ][ faces[ co ] ] ][ faces[ co ] ] = faces[ ao ]
  129. }
  130.  
  131. flagvert = true
  132. for (j = 0, jl = vertdeg[ 0 ][ faces[ co ] ]; j < jl; ++j) {
  133. if (faces[ bo ] === vertdeg[ j + 1 ][ faces[ co ] ]) {
  134. flagvert = false
  135. break
  136. }
  137. }
  138. if (flagvert) {
  139. vertdeg[ 0 ][ faces[ co ] ]++
  140. vertdeg[ vertdeg[ 0 ][ faces[ co ] ] ][ faces[ co ] ] = faces[ bo ]
  141. }
  142. }
  143.  
  144. var wt = 1.0
  145. var wt2 = 0.5
  146. var i3, vi3, vdi, wtvi, wt2vi
  147. var ssign = -1
  148. var scaleFactor = 1
  149. var outwt = 0.75 / (scaleFactor + 3.5) // area-preserving
  150.  
  151. // smoothing iterations
  152.  
  153. for (var k = 0; k < numiter; ++k) {
  154. // for each vertex
  155.  
  156. for (i = 0; i < nv; ++i) {
  157. i3 = i * 3
  158. vdi = vertdeg[ 0 ][ i ]
  159.  
  160. if (vdi < 3) {
  161. tps[ i3 ] = verts[ i3 ]
  162. tps[ i3 + 1 ] = verts[ i3 + 1 ]
  163. tps[ i3 + 2 ] = verts[ i3 + 2 ]
  164. } else if (vdi === 3 || vdi === 4) {
  165. tps[ i3 ] = 0
  166. tps[ i3 + 1 ] = 0
  167. tps[ i3 + 2 ] = 0
  168.  
  169. for (j = 0; j < vdi; ++j) {
  170. vi3 = vertdeg[ j + 1 ][ i ] * 3
  171. tps[ i3 ] += verts[ vi3 ]
  172. tps[ i3 + 1 ] += verts[ vi3 + 1 ]
  173. tps[ i3 + 2 ] += verts[ vi3 + 2 ]
  174. }
  175.  
  176. tps[ i3 ] += wt2 * verts[ i3 ]
  177. tps[ i3 + 1 ] += wt2 * verts[ i3 + 1 ]
  178. tps[ i3 + 2 ] += wt2 * verts[ i3 + 2 ]
  179.  
  180. wt2vi = wt2 + vdi
  181. tps[ i3 ] /= wt2vi
  182. tps[ i3 + 1 ] /= wt2vi
  183. tps[ i3 + 2 ] /= wt2vi
  184. } else {
  185. tps[ i3 ] = 0
  186. tps[ i3 + 1 ] = 0
  187. tps[ i3 + 2 ] = 0
  188.  
  189. for (j = 0; j < vdi; ++j) {
  190. vi3 = vertdeg[ j + 1 ][ i ] * 3
  191. tps[ i3 ] += verts[ vi3 ]
  192. tps[ i3 + 1 ] += verts[ vi3 + 1 ]
  193. tps[ i3 + 2 ] += verts[ vi3 + 2 ]
  194. }
  195.  
  196. tps[ i3 ] += wt * verts[ i3 ]
  197. tps[ i3 + 1 ] += wt * verts[ i3 + 1 ]
  198. tps[ i3 + 2 ] += wt * verts[ i3 + 2 ]
  199.  
  200. wtvi = wt + vdi
  201. tps[ i3 ] /= wtvi
  202. tps[ i3 + 1 ] /= wtvi
  203. tps[ i3 + 2 ] /= wtvi
  204. }
  205. }
  206.  
  207. verts.set(tps) // copy smoothed positions
  208.  
  209. if (inflate) {
  210. computeVertexNormals(verts, faces, norms)
  211. var nv3 = nv * 3
  212.  
  213. for (i3 = 0; i3 < nv3; i3 += 3) {
  214. // if(verts[i].inout) ssign=1;
  215. // else ssign=-1;
  216.  
  217. verts[ i3 ] += ssign * outwt * norms[ i3 ]
  218. verts[ i3 + 1 ] += ssign * outwt * norms[ i3 + 1 ]
  219. verts[ i3 + 2 ] += ssign * outwt * norms[ i3 + 2 ]
  220. }
  221. }
  222. }
  223. }
  224. laplacianSmooth.__deps = [ computeVertexNormals ]
  225.  
  226. function computeVertexNormals (position, index, normal) {
  227. var i, il
  228.  
  229. if (normal === undefined) {
  230. normal = new Float32Array(position.length)
  231. } else {
  232. // reset existing normals to zero
  233. for (i = 0, il = normal.length; i < il; i++) {
  234. normal[ i ] = 0
  235. }
  236. }
  237.  
  238. var a = new Float32Array(3)
  239. var b = new Float32Array(3)
  240. var c = new Float32Array(3)
  241. var cb = new Float32Array(3)
  242. var ab = new Float32Array(3)
  243.  
  244. if (index) {
  245. // indexed elements
  246. for (i = 0, il = index.length; i < il; i += 3) {
  247. var ai = index[ i ] * 3
  248. var bi = index[ i + 1 ] * 3
  249. var ci = index[ i + 2 ] * 3
  250.  
  251. v3fromArray(a, position, ai)
  252. v3fromArray(b, position, bi)
  253. v3fromArray(c, position, ci)
  254.  
  255. v3sub(cb, c, b)
  256. v3sub(ab, a, b)
  257. v3cross(cb, cb, ab)
  258.  
  259. normal[ ai ] += cb[ 0 ]
  260. normal[ ai + 1 ] += cb[ 1 ]
  261. normal[ ai + 2 ] += cb[ 2 ]
  262.  
  263. normal[ bi ] += cb[ 0 ]
  264. normal[ bi + 1 ] += cb[ 1 ]
  265. normal[ bi + 2 ] += cb[ 2 ]
  266.  
  267. normal[ ci ] += cb[ 0 ]
  268. normal[ ci + 1 ] += cb[ 1 ]
  269. normal[ ci + 2 ] += cb[ 2 ]
  270. }
  271. } else {
  272. // non-indexed elements (unconnected triangle soup)
  273. for (i = 0, il = position.length; i < il; i += 9) {
  274. v3fromArray(a, position, i)
  275. v3fromArray(b, position, i + 3)
  276. v3fromArray(c, position, i + 6)
  277.  
  278. v3sub(cb, c, b)
  279. v3sub(ab, a, b)
  280. v3cross(cb, cb, ab)
  281.  
  282. normal[ i ] = cb[ 0 ]
  283. normal[ i + 1 ] = cb[ 1 ]
  284. normal[ i + 2 ] = cb[ 2 ]
  285.  
  286. normal[ i + 3 ] = cb[ 0 ]
  287. normal[ i + 4 ] = cb[ 1 ]
  288. normal[ i + 5 ] = cb[ 2 ]
  289.  
  290. normal[ i + 6 ] = cb[ 0 ]
  291. normal[ i + 7 ] = cb[ 1 ]
  292. normal[ i + 8 ] = cb[ 2 ]
  293. }
  294. }
  295.  
  296. normalizeVector3array(normal)
  297.  
  298. return normal
  299. }
  300. computeVertexNormals.__deps = [
  301. v3sub, v3cross, v3fromArray, normalizeVector3array
  302. ]
  303.  
  304. function getRadiusDict (radiusList) {
  305. var radiusDict = {}
  306. for (var i = 0, il = radiusList.length; i < il; ++i) {
  307. radiusDict[ radiusList[ i ] ] = true
  308. }
  309. return radiusDict
  310. }
  311.  
  312. function getSurfaceGrid (min, max, maxRadius, scaleFactor, extraMargin) {
  313. // need margin to avoid boundary/round off effects
  314. var margin = (1 / scaleFactor) * 3
  315. margin += maxRadius
  316.  
  317. v3subScalar(min, min, extraMargin + margin)
  318. v3addScalar(max, max, extraMargin + margin)
  319.  
  320. v3multiplyScalar(min, min, scaleFactor)
  321. v3floor(min, min)
  322. v3divideScalar(min, min, scaleFactor)
  323.  
  324. v3multiplyScalar(max, max, scaleFactor)
  325. v3ceil(max, max)
  326. v3divideScalar(max, max, scaleFactor)
  327.  
  328. var dim = new Float32Array(3)
  329. v3sub(dim, max, min)
  330. v3multiplyScalar(dim, dim, scaleFactor)
  331. v3ceil(dim, dim)
  332. v3addScalar(dim, dim, 1)
  333.  
  334. var maxSize = Math.pow(10, 6) * 256
  335. var tmpSize = dim[ 0 ] * dim[ 1 ] * dim[ 2 ] * 3
  336.  
  337. if (maxSize <= tmpSize) {
  338. scaleFactor *= Math.pow(maxSize / tmpSize, 1 / 3)
  339.  
  340. v3multiplyScalar(min, min, scaleFactor)
  341. v3floor(min, min)
  342. v3divideScalar(min, min, scaleFactor)
  343.  
  344. v3multiplyScalar(max, max, scaleFactor)
  345. v3ceil(max, max)
  346. v3divideScalar(max, max, scaleFactor)
  347.  
  348. v3sub(dim, max, min)
  349. v3multiplyScalar(dim, dim, scaleFactor)
  350. v3ceil(dim, dim)
  351. v3addScalar(dim, dim, 1)
  352. }
  353.  
  354. var tran = new Float32Array(min)
  355. v3negate(tran, tran)
  356.  
  357. // coordinate transformation matrix
  358. var matrix = m4new()
  359. var mroty = m4new()
  360. m4makeRotationY(mroty, degToRad(90))
  361. m4multiply(matrix, matrix, mroty)
  362.  
  363. var mscale = m4new()
  364. m4makeScale(
  365. mscale,
  366. -1 / scaleFactor,
  367. 1 / scaleFactor,
  368. 1 / scaleFactor
  369. )
  370. m4multiply(matrix, matrix, mscale)
  371.  
  372. var mtrans = m4new()
  373. m4makeTranslation(
  374. mtrans,
  375. -scaleFactor * tran[2],
  376. -scaleFactor * tran[1],
  377. -scaleFactor * tran[0]
  378. )
  379. m4multiply(matrix, matrix, mtrans)
  380.  
  381. return {
  382. dim: dim,
  383. tran: tran,
  384. matrix: matrix,
  385. scaleFactor: scaleFactor
  386. }
  387. }
  388. getSurfaceGrid.__deps = [
  389. degToRad,
  390. v3subScalar, v3addScalar, v3divideScalar, v3multiplyScalar,
  391. v3floor, v3ceil, v3sub, v3negate,
  392. m4new, m4multiply, m4makeTranslation, m4makeScale, m4makeRotationY
  393. ]
  394.  
  395. export {
  396. laplacianSmooth,
  397. computeVertexNormals,
  398. getRadiusDict,
  399. getSurfaceGrid
  400. }