Vous ne pouvez pas sélectionner plus de 25 sujets Les noms de sujets doivent commencer par une lettre ou un nombre, peuvent contenir des tirets ('-') et peuvent comporter jusqu'à 35 caractères.

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431
  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. clampToGround: false,
  15. clampToTileset: false,
  16. interpolationType: 'Linear',
  17. interpolationDegree: 2,
  18. endDelayTime: 0.5,
  19. headingOffset: 0
  20. }
  21. const DEF_PATH_STYLE = {
  22. width: 2,
  23. material: Cesium.Color.ORANGE,
  24. clampToGround: true,
  25. depthFailMaterial: Cesium.Color.ORANGE.withAlpha(0.8)
  26. }
  27. class Track {
  28. constructor(positions, duration, callback, options) {
  29. this._id = Util.uuid()
  30. this._bid = undefined
  31. this._positions = Parse.parsePositions(positions)
  32. this._duration = duration || 20
  33. this._callback = callback
  34. this._options = {
  35. ...DEF_OPTS,
  36. ...options
  37. }
  38. this._controller = undefined
  39. this._sampledPosition = undefined
  40. this._velocityOrientation = undefined
  41. this._viewed = false
  42. this._delegate = new Cesium.Entity()
  43. this._pathPositions = []
  44. this._path = new Cesium.Entity({
  45. show: false,
  46. polyline: {
  47. positions: new Cesium.CallbackProperty(() => {
  48. return this._pathPositions
  49. }, false)
  50. }
  51. })
  52. this._positionIndex = 0
  53. this._timeLine = []
  54. this._startTime = undefined
  55. this._endTime = undefined
  56. this._trackEvent = new TrackEvent()
  57. this._trackEvent.on(TrackEventType.POST_RENDER, this._onPostRender, this)
  58. this._trackEvent.on(TrackEventType.ADD, this._onAdd, this)
  59. this._trackEvent.on(TrackEventType.REMOVE, this._onRemove, this)
  60. this._trackEvent.on(
  61. TrackEventType.RESET_TIME_LINE,
  62. this._resetTimeLine,
  63. this
  64. )
  65. this._state = State.INITIALIZED
  66. }
  67. get trackId() {
  68. return this._id
  69. }
  70. set id(id) {
  71. this._bid = id
  72. return this
  73. }
  74. get id() {
  75. return this._bid
  76. }
  77. set positions(postions) {
  78. this._positions = Parse.parsePositions(postions)
  79. this._resetTimeLine({})
  80. return this
  81. }
  82. get positions() {
  83. return this._positions
  84. }
  85. set duration(duration) {
  86. this._duration = duration
  87. this._resetTimeLine({})
  88. return this
  89. }
  90. get duration() {
  91. return this._duration
  92. }
  93. set startTime(startTime) {
  94. if (startTime instanceof Date) {
  95. this._startTime = Cesium.JulianDate.fromDate(startTime)
  96. } else {
  97. this._startTime = startTime
  98. }
  99. this._resetTimeLine({})
  100. return this
  101. }
  102. get startTime() {
  103. return this._startTime
  104. }
  105. set viewed(viewed) {
  106. this._viewed = viewed
  107. return this
  108. }
  109. get viewed() {
  110. return this._viewed
  111. }
  112. get trackEvent() {
  113. return this._trackEvent
  114. }
  115. get state() {
  116. return this._state
  117. }
  118. /**
  119. * add to entities
  120. * @param controller
  121. * @private
  122. */
  123. _onAdd(controller) {
  124. if (!controller) {
  125. return false
  126. }
  127. this._controller = controller
  128. this._controller.delegate.add(this._delegate)
  129. this._controller.delegate.add(this._path)
  130. !this._startTime && (this._startTime = Cesium.JulianDate.now())
  131. this._state = State.ADDED
  132. }
  133. /**
  134. * remove from entities
  135. * @private
  136. */
  137. _onRemove() {
  138. if (!this._controller) {
  139. return false
  140. }
  141. this._controller.delegate.remove(this._delegate)
  142. this._controller.delegate.remove(this._path)
  143. this._viewed = false
  144. this._startTime = undefined
  145. this._state = State.REMOVED
  146. }
  147. /**
  148. *
  149. * @param viewer
  150. * @param viewOption
  151. * @private
  152. */
  153. _onPostRender({ viewer, viewOption }) {
  154. if (!this._startTime || !this._endTime) {
  155. return false
  156. }
  157. let now = Cesium.JulianDate.now()
  158. if (Cesium.JulianDate.lessThanOrEquals(now, this._endTime)) {
  159. let p = this._sampledPosition.getValue(now)
  160. if (!p) {
  161. return false
  162. }
  163. this._pathPositions.push(p)
  164. if (this._options.clampToTileset) {
  165. this._delegate.position = viewer.scene.clampToHeight(p, [
  166. this._delegate
  167. ])
  168. } else {
  169. this._delegate.position = p
  170. }
  171. let orientation = this._velocityOrientation.getValue(now)
  172. if (orientation) {
  173. let quaternion = Cesium.Quaternion.fromHeadingPitchRoll(
  174. new Cesium.HeadingPitchRoll(
  175. Cesium.Math.toRadians(this._options.headingOffset || 0),
  176. 0,
  177. 0
  178. ),
  179. new Cesium.Quaternion()
  180. )
  181. this._delegate.orientation = Cesium.Quaternion.multiply(
  182. orientation,
  183. quaternion,
  184. new Cesium.Quaternion()
  185. )
  186. }
  187. let time = this._timeLine[this._positionIndex]
  188. if (time) {
  189. let timeDiff = Cesium.JulianDate.secondsDifference(now, time)
  190. if (timeDiff >= 0 && timeDiff <= 1) {
  191. let position = this._positions[this._positionIndex] || undefined
  192. if (position && orientation) {
  193. let mat = Cesium.Matrix3.fromQuaternion(orientation)
  194. let mat4 = Cesium.Matrix4.fromRotationTranslation(mat, p)
  195. let hpr = Cesium.Transforms.fixedFrameToHeadingPitchRoll(mat4)
  196. position.heading = Cesium.Math.toDegrees(hpr.heading)
  197. position.pitch = Cesium.Math.toDegrees(hpr.pitch)
  198. position.roll = Cesium.Math.toDegrees(hpr.roll)
  199. }
  200. this._callback &&
  201. this._callback(
  202. position,
  203. this._positionIndex + 1 === this._positions.length
  204. )
  205. this._positionIndex++
  206. }
  207. }
  208. }
  209. this._setCameraView(viewer, viewOption)
  210. }
  211. /**
  212. * Sets camera position
  213. * @param viewer
  214. * @param viewOption
  215. * @private
  216. */
  217. _setCameraView(viewer, viewOption) {
  218. if (!this._viewed) {
  219. return false
  220. }
  221. let now = Cesium.JulianDate.now()
  222. if (Cesium.JulianDate.greaterThan(now, this._endTime)) {
  223. viewer.camera.lookAtTransform(Cesium.Matrix4.IDENTITY)
  224. viewer.delegate.trackedEntity &&
  225. (viewer.delegate.trackedEntity = undefined)
  226. this._viewed = false
  227. } else {
  228. let p = this._sampledPosition.getValue(now)
  229. let next_p = this._sampledPosition.getValue(
  230. Cesium.JulianDate.addSeconds(now, 1 / 60, new Cesium.JulianDate())
  231. )
  232. if (p && next_p) {
  233. if (
  234. viewOption?.mode === TrackViewMode.TRACKED &&
  235. viewer.delegate?.trackedEntity?.id !== this._delegate?.id
  236. ) {
  237. viewer.delegate.trackedEntity = this._delegate
  238. } else if (viewOption?.mode === TrackViewMode.FP) {
  239. viewer.camera.lookAt(
  240. p,
  241. new Cesium.HeadingPitchRange(
  242. heading(p, next_p),
  243. Cesium.Math.toRadians(viewOption?.pitch || 0),
  244. viewOption?.range || 10
  245. )
  246. )
  247. } else if (viewOption?.mode === TrackViewMode.TP) {
  248. viewer.camera.lookAt(
  249. p,
  250. new Cesium.HeadingPitchRange(
  251. 0,
  252. Cesium.Math.toRadians(viewOption?.pitch || -90),
  253. viewOption?.range || 1000
  254. )
  255. )
  256. }
  257. }
  258. }
  259. }
  260. /**
  261. *
  262. * @param params
  263. * @returns {boolean}
  264. * @private
  265. */
  266. _resetTimeLine(params) {
  267. if (!this._startTime || !this._duration || !this._positions?.length) {
  268. return false
  269. }
  270. let interval = 0
  271. if (!params?.stopTime && !params?.duration) {
  272. let v = distance(this._positions) / this._duration
  273. this._timeLine = this._positions.map((item, index, arr) => {
  274. if (index !== 0) {
  275. interval += distance([arr[index - 1], item]) / v
  276. }
  277. return Cesium.JulianDate.addSeconds(
  278. this._startTime,
  279. interval,
  280. new Cesium.JulianDate()
  281. )
  282. })
  283. this._pathPositions = []
  284. this._positionIndex = 0
  285. } else if (params?.stopTime && params?.duration) {
  286. this._duration += params.duration
  287. this._timeLine = this._timeLine.map(item => {
  288. if (Cesium.JulianDate.greaterThan(item, params.stopTime)) {
  289. item = Cesium.JulianDate.addSeconds(
  290. item,
  291. params.duration,
  292. new Cesium.JulianDate()
  293. )
  294. }
  295. return item
  296. })
  297. }
  298. this._sampledPosition = new Cesium.SampledPositionProperty()
  299. this._sampledPosition.addSamples(
  300. this._timeLine,
  301. Transform.transformWGS84ArrayToCartesianArray(this._positions)
  302. )
  303. this._sampledPosition.forwardExtrapolationType =
  304. Cesium.ExtrapolationType.HOLD
  305. /// setInterpolationOptions
  306. if (this._options.interpolationType === 'Hermite') {
  307. this._sampledPosition.setInterpolationOptions({
  308. interpolationDegree: this._options.interpolationDegree || 2,
  309. interpolationAlgorithm: Cesium.HermitePolynomialApproximation
  310. })
  311. } else if (this._options.interpolationType === 'Linear') {
  312. this._sampledPosition.setInterpolationOptions({
  313. interpolationDegree: this._options.interpolationDegree || 1,
  314. interpolationAlgorithm: Cesium.LinearApproximation
  315. })
  316. } else if (this._options.interpolationType === 'Lagrange') {
  317. this._sampledPosition.setInterpolationOptions({
  318. interpolationDegree: this._options.interpolationDegree || 5,
  319. interpolationAlgorithm: Cesium.LagrangePolynomialApproximation
  320. })
  321. }
  322. this._velocityOrientation = new Cesium.VelocityOrientationProperty(
  323. this._sampledPosition
  324. )
  325. this._endTime = Cesium.JulianDate.addSeconds(
  326. this._timeLine[this._timeLine.length - 1],
  327. this._options.endDelayTime,
  328. new Cesium.JulianDate()
  329. )
  330. }
  331. /**
  332. * Adds Position
  333. * @param position
  334. * @param duration
  335. * @returns {Track}
  336. */
  337. addPosition(position, duration) {
  338. this._positions.push(Parse.parsePosition(position))
  339. this._duration += duration
  340. this._resetTimeLine({})
  341. return this
  342. }
  343. /**
  344. * Sets model
  345. * @param modelPath
  346. * @param style
  347. * @returns {Track}
  348. */
  349. setModel(modelPath, style) {
  350. this._delegate.model = {
  351. ...style,
  352. uri: modelPath,
  353. heightReference: this._options.clampToGround
  354. ? Cesium.HeightReference.CLAMP_TO_GROUND
  355. : Cesium.HeightReference.NONE
  356. }
  357. return this
  358. }
  359. /**
  360. * Sets billboard
  361. * @param icon
  362. * @param style
  363. * @returns {Track}
  364. */
  365. setBillboard(icon, style) {
  366. this._delegate.billboard = {
  367. ...style,
  368. image: icon,
  369. heightReference: this._options.clampToGround
  370. ? Cesium.HeightReference.CLAMP_TO_GROUND
  371. : Cesium.HeightReference.NONE
  372. }
  373. return this
  374. }
  375. /**
  376. * Sets label
  377. * @param text
  378. * @param style
  379. * @returns {Track}
  380. */
  381. setLabel(text, style) {
  382. this._delegate.label = {
  383. ...style,
  384. text: text,
  385. heightReference: this._options.clampToGround
  386. ? Cesium.HeightReference.CLAMP_TO_GROUND
  387. : Cesium.HeightReference.NONE
  388. }
  389. return this
  390. }
  391. /**
  392. *
  393. * @param visible
  394. * @param style
  395. * @returns {Track}
  396. */
  397. setPath(visible, style = {}) {
  398. this._path.show = !!visible
  399. Util.merge(this._path.polyline, DEF_PATH_STYLE, style)
  400. return this
  401. }
  402. }
  403. export default Track