util.ts 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162
  1. /**
  2. * Copyright (c) 2018-2020 mol* contributors, licensed under MIT, See LICENSE file for more info.
  3. *
  4. * @author Alexander Rose <alexander.rose@weirdbyte.de>
  5. */
  6. import { Vec3, Mat4, Mat3 } from '../mol-math/linear-algebra';
  7. import { NumberArray } from '../mol-util/type-helpers';
  8. import { arrayMax } from '../mol-util/array';
  9. export function normalizeVec3Array<T extends NumberArray> (a: T, count: number) {
  10. for (let i = 0, il = count * 3; i < il; i += 3) {
  11. const x = a[i];
  12. const y = a[i + 1];
  13. const z = a[i + 2];
  14. const s = 1 / Math.sqrt(x * x + y * y + z * z);
  15. a[i] = x * s;
  16. a[i + 1] = y * s;
  17. a[i + 2] = z * s;
  18. }
  19. return a;
  20. }
  21. const tmpV3 = Vec3.zero();
  22. export function transformPositionArray (t: Mat4, array: NumberArray, offset: number, count: number) {
  23. for (let i = 0, il = count * 3; i < il; i += 3) {
  24. Vec3.fromArray(tmpV3, array, offset + i);
  25. Vec3.transformMat4(tmpV3, tmpV3, t);
  26. Vec3.toArray(tmpV3, array, offset + i);
  27. }
  28. }
  29. export function transformDirectionArray (n: Mat3, array: NumberArray, offset: number, count: number) {
  30. for (let i = 0, il = count * 3; i < il; i += 3) {
  31. Vec3.fromArray(tmpV3, array, offset + i);
  32. Vec3.transformMat3(tmpV3, tmpV3, n);
  33. Vec3.toArray(tmpV3, array, offset + i);
  34. }
  35. }
  36. /** iterate over the entire array and apply the radius to each vertex */
  37. export function appplyRadius(vertices: NumberArray, radius: number) {
  38. for (let i = 0, il = vertices.length; i < il; i += 3) {
  39. Vec3.fromArray(tmpV3, vertices, i);
  40. Vec3.normalize(tmpV3, tmpV3);
  41. Vec3.scale(tmpV3, tmpV3, radius);
  42. Vec3.toArray(tmpV3, vertices, i);
  43. }
  44. }
  45. const a = Vec3();
  46. const b = Vec3();
  47. const c = Vec3();
  48. const cb = Vec3();
  49. const ab = Vec3();
  50. /**
  51. * indexed vertex normals weighted by triangle areas
  52. * http://www.iquilezles.org/www/articles/normals/normals.htm
  53. * - normals array must contain only zeros
  54. */
  55. export function computeIndexedVertexNormals<T extends NumberArray> (vertices: NumberArray, indices: NumberArray, normals: T, vertexCount: number, triangleCount: number) {
  56. for (let i = 0, il = triangleCount * 3; i < il; i += 3) {
  57. const ai = indices[i] * 3;
  58. const bi = indices[i + 1] * 3;
  59. const ci = indices[i + 2] * 3;
  60. Vec3.fromArray(a, vertices, ai);
  61. Vec3.fromArray(b, vertices, bi);
  62. Vec3.fromArray(c, vertices, ci);
  63. Vec3.sub(cb, c, b);
  64. Vec3.sub(ab, a, b);
  65. Vec3.cross(cb, cb, ab);
  66. normals[ai] += cb[0];
  67. normals[ai + 1] += cb[1];
  68. normals[ai + 2] += cb[2];
  69. normals[bi] += cb[0];
  70. normals[bi + 1] += cb[1];
  71. normals[bi + 2] += cb[2];
  72. normals[ci] += cb[0];
  73. normals[ci + 1] += cb[1];
  74. normals[ci + 2] += cb[2];
  75. }
  76. return normalizeVec3Array(normals, vertexCount);
  77. }
  78. /**
  79. * vertex normals for unindexed triangle soup
  80. * - normals array must contain only zeros
  81. */
  82. export function computeVertexNormals<T extends NumberArray> (vertices: NumberArray, normals: T, vertexCount: number) {
  83. for (let i = 0, il = vertexCount * 3; i < il; i += 9) {
  84. Vec3.fromArray(a, vertices, i);
  85. Vec3.fromArray(b, vertices, i + 3);
  86. Vec3.fromArray(c, vertices, i + 6);
  87. Vec3.sub(cb, c, b);
  88. Vec3.sub(ab, a, b);
  89. Vec3.cross(cb, cb, ab);
  90. normals[i] = cb[0];
  91. normals[i + 1] = cb[1];
  92. normals[i + 2] = cb[2];
  93. normals[i + 3] = cb[0];
  94. normals[i + 4] = cb[1];
  95. normals[i + 5] = cb[2];
  96. normals[i + 6] = cb[0];
  97. normals[i + 7] = cb[1];
  98. normals[i + 8] = cb[2];
  99. }
  100. return normalizeVec3Array(normals, vertexCount);
  101. }
  102. /**
  103. * Maps groups to data, range for group i is offsets[i] to offsets[i + 1]
  104. */
  105. export type GroupMapping = {
  106. /** data indices */
  107. readonly indices: ArrayLike<number>
  108. /** range for group i is offsets[i] to offsets[i + 1] */
  109. readonly offsets: ArrayLike<number>
  110. }
  111. /**
  112. * The `step` parameter allows to skip over repeated values in `groups`
  113. */
  114. export function createGroupMapping(groups: ArrayLike<number>, dataCount: number, step = 1): GroupMapping {
  115. const maxId = arrayMax(groups);
  116. const offsets = new Int32Array(maxId + 2);
  117. const bucketFill = new Int32Array(dataCount);
  118. const bucketSizes = new Int32Array(dataCount);
  119. for (let i = 0, il = dataCount * step; i < il; i += step) ++bucketSizes[groups[i]];
  120. let offset = 0;
  121. for (let i = 0; i < dataCount; i++) {
  122. offsets[i] = offset;
  123. offset += bucketSizes[i];
  124. }
  125. offsets[dataCount] = offset;
  126. const indices = new Int32Array(offset);
  127. for (let i = 0, il = dataCount * step; i < il; i += step) {
  128. const g = groups[i];
  129. const og = offsets[g] + bucketFill[g];
  130. indices[og] = i;
  131. ++bucketFill[g];
  132. }
  133. return { indices, offsets };
  134. }