scaleToGeodeticSurface.js 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126
  1. import Cartesian3 from './Cartesian3.js';
  2. import defined from './defined.js';
  3. import DeveloperError from './DeveloperError.js';
  4. import CesiumMath from './Math.js';
  5. var scaleToGeodeticSurfaceIntersection = new Cartesian3();
  6. var scaleToGeodeticSurfaceGradient = new Cartesian3();
  7. /**
  8. * Scales the provided Cartesian position along the geodetic surface normal
  9. * so that it is on the surface of this ellipsoid. If the position is
  10. * at the center of the ellipsoid, this function returns undefined.
  11. *
  12. * @param {Cartesian3} cartesian The Cartesian position to scale.
  13. * @param {Cartesian3} oneOverRadii One over radii of the ellipsoid.
  14. * @param {Cartesian3} oneOverRadiiSquared One over radii squared of the ellipsoid.
  15. * @param {Number} centerToleranceSquared Tolerance for closeness to the center.
  16. * @param {Cartesian3} [result] The object onto which to store the result.
  17. * @returns {Cartesian3} The modified result parameter, a new Cartesian3 instance if none was provided, or undefined if the position is at the center.
  18. *
  19. * @exports scaleToGeodeticSurface
  20. *
  21. * @private
  22. */
  23. function scaleToGeodeticSurface(cartesian, oneOverRadii, oneOverRadiiSquared, centerToleranceSquared, result) {
  24. //>>includeStart('debug', pragmas.debug);
  25. if (!defined(cartesian)) {
  26. throw new DeveloperError('cartesian is required.');
  27. }
  28. if (!defined(oneOverRadii)) {
  29. throw new DeveloperError('oneOverRadii is required.');
  30. }
  31. if (!defined(oneOverRadiiSquared)) {
  32. throw new DeveloperError('oneOverRadiiSquared is required.');
  33. }
  34. if (!defined(centerToleranceSquared)) {
  35. throw new DeveloperError('centerToleranceSquared is required.');
  36. }
  37. //>>includeEnd('debug');
  38. var positionX = cartesian.x;
  39. var positionY = cartesian.y;
  40. var positionZ = cartesian.z;
  41. var oneOverRadiiX = oneOverRadii.x;
  42. var oneOverRadiiY = oneOverRadii.y;
  43. var oneOverRadiiZ = oneOverRadii.z;
  44. var x2 = positionX * positionX * oneOverRadiiX * oneOverRadiiX;
  45. var y2 = positionY * positionY * oneOverRadiiY * oneOverRadiiY;
  46. var z2 = positionZ * positionZ * oneOverRadiiZ * oneOverRadiiZ;
  47. // Compute the squared ellipsoid norm.
  48. var squaredNorm = x2 + y2 + z2;
  49. var ratio = Math.sqrt(1.0 / squaredNorm);
  50. // As an initial approximation, assume that the radial intersection is the projection point.
  51. var intersection = Cartesian3.multiplyByScalar(cartesian, ratio, scaleToGeodeticSurfaceIntersection);
  52. // If the position is near the center, the iteration will not converge.
  53. if (squaredNorm < centerToleranceSquared) {
  54. return !isFinite(ratio) ? undefined : Cartesian3.clone(intersection, result);
  55. }
  56. var oneOverRadiiSquaredX = oneOverRadiiSquared.x;
  57. var oneOverRadiiSquaredY = oneOverRadiiSquared.y;
  58. var oneOverRadiiSquaredZ = oneOverRadiiSquared.z;
  59. // Use the gradient at the intersection point in place of the true unit normal.
  60. // The difference in magnitude will be absorbed in the multiplier.
  61. var gradient = scaleToGeodeticSurfaceGradient;
  62. gradient.x = intersection.x * oneOverRadiiSquaredX * 2.0;
  63. gradient.y = intersection.y * oneOverRadiiSquaredY * 2.0;
  64. gradient.z = intersection.z * oneOverRadiiSquaredZ * 2.0;
  65. // Compute the initial guess at the normal vector multiplier, lambda.
  66. var lambda = (1.0 - ratio) * Cartesian3.magnitude(cartesian) / (0.5 * Cartesian3.magnitude(gradient));
  67. var correction = 0.0;
  68. var func;
  69. var denominator;
  70. var xMultiplier;
  71. var yMultiplier;
  72. var zMultiplier;
  73. var xMultiplier2;
  74. var yMultiplier2;
  75. var zMultiplier2;
  76. var xMultiplier3;
  77. var yMultiplier3;
  78. var zMultiplier3;
  79. do {
  80. lambda -= correction;
  81. xMultiplier = 1.0 / (1.0 + lambda * oneOverRadiiSquaredX);
  82. yMultiplier = 1.0 / (1.0 + lambda * oneOverRadiiSquaredY);
  83. zMultiplier = 1.0 / (1.0 + lambda * oneOverRadiiSquaredZ);
  84. xMultiplier2 = xMultiplier * xMultiplier;
  85. yMultiplier2 = yMultiplier * yMultiplier;
  86. zMultiplier2 = zMultiplier * zMultiplier;
  87. xMultiplier3 = xMultiplier2 * xMultiplier;
  88. yMultiplier3 = yMultiplier2 * yMultiplier;
  89. zMultiplier3 = zMultiplier2 * zMultiplier;
  90. func = x2 * xMultiplier2 + y2 * yMultiplier2 + z2 * zMultiplier2 - 1.0;
  91. // "denominator" here refers to the use of this expression in the velocity and acceleration
  92. // computations in the sections to follow.
  93. denominator = x2 * xMultiplier3 * oneOverRadiiSquaredX + y2 * yMultiplier3 * oneOverRadiiSquaredY + z2 * zMultiplier3 * oneOverRadiiSquaredZ;
  94. var derivative = -2.0 * denominator;
  95. correction = func / derivative;
  96. } while (Math.abs(func) > CesiumMath.EPSILON12);
  97. if (!defined(result)) {
  98. return new Cartesian3(positionX * xMultiplier, positionY * yMultiplier, positionZ * zMultiplier);
  99. }
  100. result.x = positionX * xMultiplier;
  101. result.y = positionY * yMultiplier;
  102. result.z = positionZ * zMultiplier;
  103. return result;
  104. }
  105. export default scaleToGeodeticSurface;