TerrainOffsetProperty.js 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246
  1. import Cartesian3 from "../Core/Cartesian3.js";
  2. import Cartographic from "../Core/Cartographic.js";
  3. import Check from "../Core/Check.js";
  4. import defined from "../Core/defined.js";
  5. import destroyObject from "../Core/destroyObject.js";
  6. import Event from "../Core/Event.js";
  7. import Iso8601 from "../Core/Iso8601.js";
  8. import CesiumMath from "../Core/Math.js";
  9. import HeightReference from "../Scene/HeightReference.js";
  10. import SceneMode from "../Scene/SceneMode.js";
  11. import Property from "./Property.js";
  12. const scratchPosition = new Cartesian3();
  13. const scratchCarto = new Cartographic();
  14. /**
  15. * @private
  16. */
  17. function TerrainOffsetProperty(
  18. scene,
  19. positionProperty,
  20. heightReferenceProperty,
  21. extrudedHeightReferenceProperty
  22. ) {
  23. //>>includeStart('debug', pragmas.debug);
  24. Check.defined("scene", scene);
  25. Check.defined("positionProperty", positionProperty);
  26. //>>includeEnd('debug');
  27. this._scene = scene;
  28. this._heightReference = heightReferenceProperty;
  29. this._extrudedHeightReference = extrudedHeightReferenceProperty;
  30. this._positionProperty = positionProperty;
  31. this._position = new Cartesian3();
  32. this._cartographicPosition = new Cartographic();
  33. this._normal = new Cartesian3();
  34. this._definitionChanged = new Event();
  35. this._terrainHeight = 0;
  36. this._removeCallbackFunc = undefined;
  37. this._removeEventListener = undefined;
  38. this._removeModeListener = undefined;
  39. const that = this;
  40. if (defined(scene.globe)) {
  41. this._removeEventListener = scene.terrainProviderChanged.addEventListener(
  42. function () {
  43. that._updateClamping();
  44. }
  45. );
  46. this._removeModeListener = scene.morphComplete.addEventListener(
  47. function () {
  48. that._updateClamping();
  49. }
  50. );
  51. }
  52. if (positionProperty.isConstant) {
  53. const position = positionProperty.getValue(
  54. Iso8601.MINIMUM_VALUE,
  55. scratchPosition
  56. );
  57. if (
  58. !defined(position) ||
  59. Cartesian3.equals(position, Cartesian3.ZERO) ||
  60. !defined(scene.globe)
  61. ) {
  62. return;
  63. }
  64. this._position = Cartesian3.clone(position, this._position);
  65. this._updateClamping();
  66. this._normal = scene.globe.ellipsoid.geodeticSurfaceNormal(
  67. position,
  68. this._normal
  69. );
  70. }
  71. }
  72. Object.defineProperties(TerrainOffsetProperty.prototype, {
  73. /**
  74. * Gets a value indicating if this property is constant.
  75. * @memberof TerrainOffsetProperty.prototype
  76. *
  77. * @type {boolean}
  78. * @readonly
  79. */
  80. isConstant: {
  81. get: function () {
  82. return false;
  83. },
  84. },
  85. /**
  86. * Gets the event that is raised whenever the definition of this property changes.
  87. * @memberof TerrainOffsetProperty.prototype
  88. *
  89. * @type {Event}
  90. * @readonly
  91. */
  92. definitionChanged: {
  93. get: function () {
  94. return this._definitionChanged;
  95. },
  96. },
  97. });
  98. /**
  99. * @private
  100. */
  101. TerrainOffsetProperty.prototype._updateClamping = function () {
  102. if (defined(this._removeCallbackFunc)) {
  103. this._removeCallbackFunc();
  104. }
  105. const scene = this._scene;
  106. const globe = scene.globe;
  107. const position = this._position;
  108. if (!defined(globe) || Cartesian3.equals(position, Cartesian3.ZERO)) {
  109. this._terrainHeight = 0;
  110. return;
  111. }
  112. const ellipsoid = globe.ellipsoid;
  113. const surface = globe._surface;
  114. const that = this;
  115. const cartographicPosition = ellipsoid.cartesianToCartographic(
  116. position,
  117. this._cartographicPosition
  118. );
  119. const height = globe.getHeight(cartographicPosition);
  120. if (defined(height)) {
  121. this._terrainHeight = height;
  122. } else {
  123. this._terrainHeight = 0;
  124. }
  125. function updateFunction(clampedPosition) {
  126. if (scene.mode === SceneMode.SCENE3D) {
  127. const carto = ellipsoid.cartesianToCartographic(
  128. clampedPosition,
  129. scratchCarto
  130. );
  131. that._terrainHeight = carto.height;
  132. } else {
  133. that._terrainHeight = clampedPosition.x;
  134. }
  135. that.definitionChanged.raiseEvent();
  136. }
  137. this._removeCallbackFunc = surface.updateHeight(
  138. cartographicPosition,
  139. updateFunction
  140. );
  141. };
  142. /**
  143. * Gets the height relative to the terrain based on the positions.
  144. *
  145. * @returns {Cartesian3} The offset
  146. */
  147. TerrainOffsetProperty.prototype.getValue = function (time, result) {
  148. const heightReference = Property.getValueOrDefault(
  149. this._heightReference,
  150. time,
  151. HeightReference.NONE
  152. );
  153. const extrudedHeightReference = Property.getValueOrDefault(
  154. this._extrudedHeightReference,
  155. time,
  156. HeightReference.NONE
  157. );
  158. if (
  159. heightReference === HeightReference.NONE &&
  160. extrudedHeightReference !== HeightReference.RELATIVE_TO_GROUND
  161. ) {
  162. this._position = Cartesian3.clone(Cartesian3.ZERO, this._position);
  163. return Cartesian3.clone(Cartesian3.ZERO, result);
  164. }
  165. if (this._positionProperty.isConstant) {
  166. return Cartesian3.multiplyByScalar(
  167. this._normal,
  168. this._terrainHeight,
  169. result
  170. );
  171. }
  172. const scene = this._scene;
  173. const position = this._positionProperty.getValue(time, scratchPosition);
  174. if (
  175. !defined(position) ||
  176. Cartesian3.equals(position, Cartesian3.ZERO) ||
  177. !defined(scene.globe)
  178. ) {
  179. return Cartesian3.clone(Cartesian3.ZERO, result);
  180. }
  181. if (
  182. Cartesian3.equalsEpsilon(this._position, position, CesiumMath.EPSILON10)
  183. ) {
  184. return Cartesian3.multiplyByScalar(
  185. this._normal,
  186. this._terrainHeight,
  187. result
  188. );
  189. }
  190. this._position = Cartesian3.clone(position, this._position);
  191. this._updateClamping();
  192. const normal = scene.globe.ellipsoid.geodeticSurfaceNormal(
  193. position,
  194. this._normal
  195. );
  196. return Cartesian3.multiplyByScalar(normal, this._terrainHeight, result);
  197. };
  198. TerrainOffsetProperty.prototype.isDestroyed = function () {
  199. return false;
  200. };
  201. TerrainOffsetProperty.prototype.destroy = function () {
  202. if (defined(this._removeEventListener)) {
  203. this._removeEventListener();
  204. }
  205. if (defined(this._removeModeListener)) {
  206. this._removeModeListener();
  207. }
  208. if (defined(this._removeCallbackFunc)) {
  209. this._removeCallbackFunc();
  210. }
  211. return destroyObject(this);
  212. };
  213. /**
  214. * A function which creates one or more providers.
  215. * @callback TerrainOffsetProperty.PositionFunction
  216. * @param {JulianDate} time The clock time at which to retrieve the position
  217. * @param {Cartesian3} result The result position
  218. * @returns {Cartesian3} The position at which to do the terrain height check
  219. */
  220. export default TerrainOffsetProperty;