Reference Source

src/viewer/scene/math/rtcCoords.js

  1. import {math} from './math.js';
  2.  
  3. const tempVec3a = math.vec3();
  4. const tempVec4 = math.vec4();
  5.  
  6. /**
  7. * Given a view matrix and a relative-to-center (RTC) coordinate origin, returns a view matrix
  8. * to transform RTC coordinates to View-space.
  9. *
  10. * The returned view matrix is
  11. *
  12. * @private
  13. */
  14. const createRTCViewMat = (function () {
  15.  
  16. const tempMat = new Float64Array(16);
  17. const rtcCenterWorld = new Float64Array(4);
  18. const rtcCenterView = new Float64Array(4);
  19.  
  20. return function (viewMat, rtcCenter, rtcViewMat) {
  21. rtcViewMat = rtcViewMat || tempMat;
  22. rtcCenterWorld[0] = rtcCenter[0];
  23. rtcCenterWorld[1] = rtcCenter[1];
  24. rtcCenterWorld[2] = rtcCenter[2];
  25. rtcCenterWorld[3] = 1;
  26. math.transformVec4(viewMat, rtcCenterWorld, rtcCenterView);
  27. math.setMat4Translation(viewMat, rtcCenterView, rtcViewMat);
  28. return rtcViewMat.slice ();
  29. }
  30. }());
  31.  
  32. /**
  33. * Converts a World-space 3D position to RTC.
  34. *
  35. * Given a double-precision World-space position, returns a double-precision relative-to-center (RTC) center pos
  36. * and a single-precision offset fom that center.
  37. * @private
  38. * @param {Float64Array} worldPos The World-space position.
  39. * @param {Float64Array} rtcCenter Double-precision relative-to-center (RTC) center pos.
  40. * @param {Float32Array} rtcPos Single-precision offset fom that center.
  41. */
  42. function worldToRTCPos(worldPos, rtcCenter, rtcPos) {
  43.  
  44. const xHigh = Float32Array.from([worldPos[0]])[0];
  45. const xLow = worldPos[0] - xHigh;
  46.  
  47. const yHigh = Float32Array.from([worldPos[1]])[0];
  48. const yLow = worldPos[1] - yHigh;
  49.  
  50. const zHigh = Float32Array.from([worldPos[2]])[0];
  51. const zLow = worldPos[2] - zHigh;
  52.  
  53. rtcCenter[0] = xHigh;
  54. rtcCenter[1] = yHigh;
  55. rtcCenter[2] = zHigh;
  56.  
  57. rtcPos[0] = xLow;
  58. rtcPos[1] = yLow;
  59. rtcPos[2] = zLow;
  60. }
  61.  
  62.  
  63. /**
  64. * Converts a flat array of double-precision positions to RTC positions, if necessary.
  65. *
  66. * Conversion is necessary if the coordinates have values larger than can be expressed at single-precision. When
  67. * that's the case, then this function will compute the RTC coordinates and RTC center and return true. Otherwise
  68. * this function does nothing and returns false.
  69. *
  70. * When computing the RTC position, this function uses a modulus operation to ensure that, whenever possible,
  71. * identical RTC centers are reused for different positions arrays.
  72. *
  73. * @private
  74. * @param {Float64Array} worldPositions Flat array of World-space 3D positions.
  75. * @param {Float64Array} rtcPositions Outputs the computed flat array of 3D RTC positions.
  76. * @param {Float64Array} rtcCenter Outputs the computed double-precision relative-to-center (RTC) center pos.
  77. * @param {Number} [cellSize=10000000] The size of each coordinate cell within the RTC coordinate system.
  78. * @returns {Boolean} ````True```` if the positions actually needed conversion to RTC, else ````false````. When
  79. * ````false````, we can safely ignore the data returned in ````rtcPositions```` and ````rtcCenter````,
  80. * since ````rtcCenter```` will equal ````[0,0,0]````, and ````rtcPositions```` will contain identical values to ````positions````.
  81. */
  82. function worldToRTCPositions(worldPositions, rtcPositions, rtcCenter, cellSize = 1000) {
  83.  
  84. const center = math.getPositionsCenter(worldPositions, tempVec3a);
  85.  
  86. const rtcCenterX = Math.round(center[0] / cellSize) * cellSize;
  87. const rtcCenterY = Math.round(center[1] / cellSize) * cellSize;
  88. const rtcCenterZ = Math.round(center[2] / cellSize) * cellSize;
  89.  
  90. rtcCenter[0] = rtcCenterX;
  91. rtcCenter[1] = rtcCenterY;
  92. rtcCenter[2] = rtcCenterZ;
  93.  
  94. const rtcNeeded = (rtcCenter[0] !== 0 || rtcCenter[1] !== 0 || rtcCenter[2] !== 0);
  95.  
  96. if (rtcNeeded) {
  97. for (let i = 0, len = worldPositions.length; i < len; i += 3) {
  98. rtcPositions[i + 0] = worldPositions[i + 0] - rtcCenterX;
  99. rtcPositions[i + 1] = worldPositions[i + 1] - rtcCenterY;
  100. rtcPositions[i + 2] = worldPositions[i + 2] - rtcCenterZ;
  101. }
  102. }
  103.  
  104. return rtcNeeded;
  105. }
  106.  
  107. /**
  108. * Converts an RTC 3D position to World-space.
  109. *
  110. * @private
  111. * @param {Float64Array} rtcCenter Double-precision relative-to-center (RTC) center pos.
  112. * @param {Float32Array} rtcPos Single-precision offset fom that center.
  113. * @param {Float64Array} worldPos The World-space position.
  114. */
  115. function rtcToWorldPos(rtcCenter, rtcPos, worldPos) {
  116. worldPos[0] = rtcCenter[0] + rtcPos[0];
  117. worldPos[1] = rtcCenter[1] + rtcPos[1];
  118. worldPos[2] = rtcCenter[2] + rtcPos[2];
  119. return worldPos;
  120. }
  121.  
  122. /**
  123. * Given a 3D plane defined by distance from origin and direction, and an RTC center position,
  124. * return a plane position that is relative to the RTC center.
  125. *
  126. * @private
  127. * @param dist
  128. * @param dir
  129. * @param rtcCenter
  130. * @param rtcPlanePos
  131. * @returns {*}
  132. */
  133. function getPlaneRTCPos(dist, dir, rtcOrigin, rtcPlanePos, originMatrix) {
  134. const rtcCenter = (originMatrix
  135. ? (tempVec4.set(rtcOrigin, 0), tempVec4[3] = 1, math.mulMat4v4(originMatrix, tempVec4, tempVec4))
  136. : rtcOrigin);
  137. const rtcCenterToPlaneDist = math.dotVec3(dir, rtcCenter) + dist;
  138. const dirNormalized = math.normalizeVec3(dir, tempVec3a);
  139. math.mulVec3Scalar(dirNormalized, -rtcCenterToPlaneDist, rtcPlanePos);
  140. return rtcPlanePos;
  141. }
  142.  
  143. export {createRTCViewMat, worldToRTCPos, worldToRTCPositions, rtcToWorldPos, getPlaneRTCPos};