You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359
  1. /**
  2. * @Author: Caven
  3. * @Date: 2020-01-19 11:21:48
  4. */
  5. import { Cesium } from '@dc-modules/namespace'
  6. import { TrackEvent, TrackEventType } from '@dc-modules/event'
  7. import State from '@dc-modules/state/State'
  8. import Parse from '@dc-modules/parse/Parse'
  9. import { Util } from '@dc-modules/utils'
  10. import { Transform } from '@dc-modules/transform'
  11. import { heading, distance } from '@dc-modules/math'
  12. import TrackViewMode from './TrackViewMode'
  13. const DEF_OPTS = {
  14. showPath: false,
  15. pathWidth: 1,
  16. pathMaterial: Cesium.Color.ORANGE.withAlpha(0.8),
  17. pathLeadTime: 1,
  18. clampToGround: false,
  19. clampToTileset: false
  20. }
  21. class Track {
  22. constructor(positions, duration, callback, options) {
  23. this._id = Util.uuid()
  24. this._bid = undefined
  25. this._positions = Parse.parsePositions(positions)
  26. this._duration = duration || 20
  27. this._callback = callback
  28. this._options = {
  29. ...DEF_OPTS,
  30. ...options
  31. }
  32. this._controller = undefined
  33. this._viewed = false
  34. this._delegate = new Cesium.Entity()
  35. this._positionIndex = 0
  36. this._timeLine = []
  37. this._startTime = undefined
  38. this._endTime = undefined
  39. this._trackEvent = new TrackEvent()
  40. this._trackEvent.on(TrackEventType.POST_RENDER, this._onPostRender, this)
  41. this._trackEvent.on(TrackEventType.ADD, this._onAdd, this)
  42. this._trackEvent.on(TrackEventType.REMOVE, this._onRemove, this)
  43. this._state = State.INITIALIZED
  44. }
  45. get trackId() {
  46. return this._id
  47. }
  48. set id(id) {
  49. this._bid = id
  50. return this
  51. }
  52. get id() {
  53. return this._bid
  54. }
  55. set positions(postions) {
  56. this._positions = Parse.parsePositions(postions)
  57. this._resetTimeLine()
  58. return this
  59. }
  60. get positions() {
  61. return this._positions
  62. }
  63. set duration(duration) {
  64. this._duration = duration
  65. this._resetTimeLine()
  66. return this
  67. }
  68. get duration() {
  69. return this._duration
  70. }
  71. set startTime(startTime) {
  72. if (startTime instanceof Date) {
  73. this._startTime = Cesium.JulianDate.fromDate(startTime)
  74. } else {
  75. this._startTime = startTime
  76. }
  77. this._resetTimeLine()
  78. return this
  79. }
  80. get startTime() {
  81. return this._startTime
  82. }
  83. set viewed(viewed) {
  84. this._viewed = viewed
  85. return this
  86. }
  87. get viewed() {
  88. return this._viewed
  89. }
  90. get trackEvent() {
  91. return this._trackEvent
  92. }
  93. get state() {
  94. return this._state
  95. }
  96. /**
  97. * add to entities
  98. * @param controller
  99. * @private
  100. */
  101. _onAdd(controller) {
  102. if (!controller) {
  103. return false
  104. }
  105. this._controller = controller
  106. this._controller.delegate.add(this._delegate)
  107. !this._startTime && (this._startTime = Cesium.JulianDate.now())
  108. this._state = State.ADDED
  109. }
  110. /**
  111. * remove from entities
  112. * @private
  113. */
  114. _onRemove() {
  115. if (this._controller) {
  116. this._controller.delegate.remove(this._delegate)
  117. }
  118. this._viewed = false
  119. this._state = State.REMOVED
  120. }
  121. /**
  122. *
  123. * @param viewer
  124. * @param viewOption
  125. * @private
  126. */
  127. _onPostRender({ viewer, viewOption }) {
  128. if (!this._startTime || !this._endTime) {
  129. return false
  130. }
  131. let now = Cesium.JulianDate.now()
  132. if (Cesium.JulianDate.lessThan(now, this._endTime)) {
  133. if (this._options.clampToTileset) {
  134. this._delegate.position = viewer.scene.clampToHeight(
  135. this._sampledPosition.getValue(now),
  136. [this._delegate]
  137. )
  138. } else {
  139. this._delegate.position = this._sampledPosition.getValue(now)
  140. }
  141. let time = this._timeLine[this._positionIndex]
  142. if (time) {
  143. let timeDiff = Cesium.JulianDate.secondsDifference(now, time)
  144. if (timeDiff >= 0 && timeDiff <= 1) {
  145. let position = this._positions[this._positionIndex] || undefined
  146. if (position) {
  147. let mat = Cesium.Matrix3.fromQuaternion(
  148. this._delegate.orientation.getValue(now)
  149. )
  150. let mat4 = Cesium.Matrix4.fromRotationTranslation(
  151. mat,
  152. this._sampledPosition.getValue(now)
  153. )
  154. let hpr = Cesium.Transforms.fixedFrameToHeadingPitchRoll(mat4)
  155. position.heading = Cesium.Math.toDegrees(hpr.heading)
  156. position.pitch = Cesium.Math.toDegrees(hpr.pitch)
  157. position.roll = Cesium.Math.toDegrees(hpr.roll)
  158. }
  159. this._callback &&
  160. this._callback(
  161. position,
  162. this._positionIndex + 1 === this._positions.length
  163. )
  164. this._positionIndex += 1
  165. }
  166. }
  167. }
  168. this._setCameraView(viewer, viewOption)
  169. }
  170. /**
  171. * Sets camera position
  172. * @param viewer
  173. * @param viewOption
  174. * @private
  175. */
  176. _setCameraView(viewer, viewOption) {
  177. if (!this._viewed) {
  178. return false
  179. }
  180. let now = Cesium.JulianDate.now()
  181. if (Cesium.JulianDate.greaterThan(now, this._endTime)) {
  182. viewer.camera.lookAtTransform(Cesium.Matrix4.IDENTITY)
  183. viewer.delegate.trackedEntity &&
  184. (viewer.delegate.trackedEntity = undefined)
  185. this._viewed = false
  186. } else {
  187. let p = this._sampledPosition.getValue(now)
  188. let next_p = this._sampledPosition.getValue(
  189. Cesium.JulianDate.addSeconds(now, 1 / 60, new Cesium.JulianDate())
  190. )
  191. if (p && next_p) {
  192. if (
  193. viewOption?.mode === TrackViewMode.TRACKED &&
  194. viewer.delegate?.trackedEntity?.id !== this._delegate?.id
  195. ) {
  196. viewer.delegate.trackedEntity = this._delegate
  197. } else if (viewOption?.mode === TrackViewMode.FP) {
  198. viewer.camera.lookAt(
  199. p,
  200. new Cesium.HeadingPitchRange(
  201. heading(p, next_p),
  202. Cesium.Math.toRadians(viewOption?.pitch || 0),
  203. viewOption?.range || 10
  204. )
  205. )
  206. } else if (viewOption?.mode === TrackViewMode.TP) {
  207. viewer.camera.lookAt(
  208. p,
  209. new Cesium.HeadingPitchRange(
  210. 0,
  211. Cesium.Math.toRadians(viewOption?.pitch || -90),
  212. viewOption?.range || 1000
  213. )
  214. )
  215. }
  216. }
  217. }
  218. }
  219. /**
  220. *
  221. * @param params
  222. * @returns {boolean}
  223. * @private
  224. */
  225. _resetTimeLine(params) {
  226. if (!this._startTime || !this._duration || !this._positions?.length) {
  227. return false
  228. }
  229. let interval = 0
  230. let v = distance(this._positions) / this._duration
  231. this._timeLine = this._positions.map((item, index, arr) => {
  232. if (index !== 0) {
  233. interval += distance([arr[index - 1], item]) / v
  234. }
  235. return Cesium.JulianDate.addSeconds(
  236. this._startTime,
  237. interval,
  238. new Cesium.JulianDate()
  239. )
  240. })
  241. if (params?.stopTime && params?.duration) {
  242. this._duration += params.duration
  243. this._timeLine = this._timeLine.map(item => {
  244. if (Cesium.JulianDate.greaterThan(item, params.stopTime)) {
  245. item = Cesium.JulianDate.addSeconds(
  246. item,
  247. params.stopTime,
  248. new Cesium.JulianDate()
  249. )
  250. }
  251. return item
  252. })
  253. }
  254. this._sampledPosition = new Cesium.SampledPositionProperty()
  255. this._sampledPosition.addSamples(
  256. this._timeLine,
  257. Transform.transformWGS84ArrayToCartesianArray(this._positions)
  258. )
  259. this._sampledPosition.forwardExtrapolationType =
  260. Cesium.ExtrapolationType.HOLD
  261. this._sampledPosition.setInterpolationOptions({
  262. interpolationDegree: 5,
  263. interpolationAlgorithm: Cesium.HermitePolynomialApproximation
  264. })
  265. this._delegate.orientation = new Cesium.VelocityOrientationProperty(
  266. this._sampledPosition
  267. )
  268. this._endTime = this._timeLine[this._timeLine.length - 1]
  269. }
  270. /**
  271. * Adds Position
  272. * @param position
  273. * @param duration
  274. * @returns {Track}
  275. */
  276. addPosition(position, duration) {
  277. this._positions.push(Parse.parsePosition(position))
  278. this._duration += duration
  279. this._resetTimeLine()
  280. return this
  281. }
  282. /**
  283. * Sets model
  284. * @param modelPath
  285. * @param style
  286. * @returns {Track}
  287. */
  288. setModel(modelPath, style) {
  289. this._delegate.model = {
  290. ...style,
  291. uri: modelPath,
  292. heightReference: this._options.clampToGround
  293. ? Cesium.HeightReference.CLAMP_TO_GROUND
  294. : Cesium.HeightReference.NONE
  295. }
  296. return this
  297. }
  298. /**
  299. * Sets billboard
  300. * @param icon
  301. * @param style
  302. * @returns {Track}
  303. */
  304. setBillboard(icon, style) {
  305. this._delegate.billboard = {
  306. ...style,
  307. image: icon,
  308. heightReference: this._options.clampToGround
  309. ? Cesium.HeightReference.CLAMP_TO_GROUND
  310. : Cesium.HeightReference.NONE
  311. }
  312. return this
  313. }
  314. /**
  315. * Sets label
  316. * @param text
  317. * @param style
  318. * @returns {Track}
  319. */
  320. setLabel(text, style) {
  321. this._delegate.label = {
  322. ...style,
  323. text: text,
  324. heightReference: this._options.clampToGround
  325. ? Cesium.HeightReference.CLAMP_TO_GROUND
  326. : Cesium.HeightReference.NONE
  327. }
  328. return this
  329. }
  330. setPath() {}
  331. }
  332. export default Track