bruce-cesium 5.9.6 → 5.9.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/bruce-cesium.es5.js +327 -261
- package/dist/bruce-cesium.es5.js.map +1 -1
- package/dist/bruce-cesium.umd.js +325 -259
- package/dist/bruce-cesium.umd.js.map +1 -1
- package/dist/lib/bruce-cesium.js +1 -1
- package/dist/lib/rendering/cesium-animated-property.js +187 -163
- package/dist/lib/rendering/cesium-animated-property.js.map +1 -1
- package/dist/lib/rendering/entity-render-engine-model3d.js +35 -36
- package/dist/lib/rendering/entity-render-engine-model3d.js.map +1 -1
- package/dist/lib/rendering/entity-render-engine-point.js +102 -58
- package/dist/lib/rendering/entity-render-engine-point.js.map +1 -1
- package/dist/types/bruce-cesium.d.ts +1 -1
- package/dist/types/rendering/cesium-animated-property.d.ts +16 -25
- package/package.json +1 -1
package/dist/lib/bruce-cesium.js
CHANGED
|
@@ -72,5 +72,5 @@ __exportStar(require("./widgets/controls-view-bar/widget-control-view-bar-search
|
|
|
72
72
|
__exportStar(require("./widgets/widget-left-panel"), exports);
|
|
73
73
|
__exportStar(require("./widgets/tabs-left-panel/widget-left-panel-tab"), exports);
|
|
74
74
|
__exportStar(require("./widgets/tabs-left-panel/widget-left-panel-tab-bookmarks"), exports);
|
|
75
|
-
exports.VERSION = "5.9.
|
|
75
|
+
exports.VERSION = "5.9.8";
|
|
76
76
|
//# sourceMappingURL=bruce-cesium.js.map
|
|
@@ -372,19 +372,18 @@ var CesiumAnimatedProperty;
|
|
|
372
372
|
*/
|
|
373
373
|
class AnimatePositionSeries {
|
|
374
374
|
constructor(params) {
|
|
375
|
-
|
|
376
|
-
this.
|
|
377
|
-
this.
|
|
378
|
-
this.
|
|
379
|
-
this.
|
|
380
|
-
this.
|
|
381
|
-
|
|
375
|
+
this.currentPos = null;
|
|
376
|
+
this.currentVelocity = new Cesium.Cartesian3(0, 0, 0);
|
|
377
|
+
this.smoothingFactor = 0.5;
|
|
378
|
+
this.positionHistory = [];
|
|
379
|
+
this.maxHistorySize = 10;
|
|
380
|
+
this.averageSpeed = 0;
|
|
381
|
+
this.averageTimeInterval = 0;
|
|
382
|
+
this.lastUpdateTime = null;
|
|
382
383
|
this.lastDesiredPosIndex = -1;
|
|
383
384
|
this.lastDesiredNextIndex = -1;
|
|
384
|
-
// Series data for rendering path
|
|
385
385
|
this.lastCalcSeriesPos3d = [];
|
|
386
386
|
this.lastCalcSeriesTime = null;
|
|
387
|
-
// Orientation cache.
|
|
388
387
|
this.lastCalcOrient = null;
|
|
389
388
|
this.lastCalcOrientTime = null;
|
|
390
389
|
this.viewer = params.viewer;
|
|
@@ -393,25 +392,23 @@ var CesiumAnimatedProperty;
|
|
|
393
392
|
this.roll = params.roll || 0;
|
|
394
393
|
this.processHeadings();
|
|
395
394
|
this.sortPositions();
|
|
396
|
-
// Initialize animation from starting position if provided.
|
|
397
|
-
if (params.animateFromPos3d) {
|
|
398
|
-
this.animationStartPos = params.animateFromPos3d;
|
|
399
|
-
const currentTime = Date.now();
|
|
400
|
-
const providedTime = params.animateFromPos3dTimeStart || 0;
|
|
401
|
-
// Check if the provided timestamp is stale.
|
|
402
|
-
if (!providedTime || (currentTime - providedTime) >= this.animationDuration) {
|
|
403
|
-
this.animationStartTime = currentTime;
|
|
404
|
-
}
|
|
405
|
-
else {
|
|
406
|
-
this.animationStartTime = providedTime;
|
|
407
|
-
}
|
|
408
|
-
}
|
|
409
395
|
}
|
|
410
396
|
AddPosition(pos) {
|
|
411
397
|
if (!pos || !pos.pos3d || !pos.dateTime) {
|
|
412
398
|
console.warn("Invalid position provided to AnimatePositionSeries.");
|
|
413
399
|
return;
|
|
414
400
|
}
|
|
401
|
+
const now = Date.now();
|
|
402
|
+
const posTime = pos.dateTime.getTime();
|
|
403
|
+
this.positionHistory.push({
|
|
404
|
+
pos: pos.pos3d.clone(),
|
|
405
|
+
time: posTime,
|
|
406
|
+
realTime: now
|
|
407
|
+
});
|
|
408
|
+
if (this.positionHistory.length > this.maxHistorySize) {
|
|
409
|
+
this.positionHistory.shift();
|
|
410
|
+
}
|
|
411
|
+
this.analyzeMovementPatterns();
|
|
415
412
|
this.positions.push(pos);
|
|
416
413
|
this.processHeadings();
|
|
417
414
|
this.sortPositions();
|
|
@@ -422,12 +419,70 @@ var CesiumAnimatedProperty;
|
|
|
422
419
|
this.roll = roll;
|
|
423
420
|
this.invalidateCache();
|
|
424
421
|
}
|
|
425
|
-
GetAnimateFromDateTime() {
|
|
426
|
-
return this.animationStartTime;
|
|
427
|
-
}
|
|
428
422
|
GetPositions() {
|
|
429
423
|
return this.positions;
|
|
430
424
|
}
|
|
425
|
+
analyzeMovementPatterns() {
|
|
426
|
+
if (this.positionHistory.length < 2) {
|
|
427
|
+
return;
|
|
428
|
+
}
|
|
429
|
+
let totalDistance = 0;
|
|
430
|
+
let totalTimeSpan = 0;
|
|
431
|
+
let totalRealTimeSpan = 0;
|
|
432
|
+
let validSegments = 0;
|
|
433
|
+
for (let i = 1; i < this.positionHistory.length; i++) {
|
|
434
|
+
const prev = this.positionHistory[i - 1];
|
|
435
|
+
const curr = this.positionHistory[i];
|
|
436
|
+
const distance = Cesium.Cartesian3.distance(prev.pos, curr.pos);
|
|
437
|
+
const timeSpan = Math.abs(curr.time - prev.time) / 1000.0;
|
|
438
|
+
const realTimeSpan = Math.abs(curr.realTime - prev.realTime) / 1000.0;
|
|
439
|
+
if (distance > 0.1 && timeSpan > 0.01) {
|
|
440
|
+
totalDistance += distance;
|
|
441
|
+
totalTimeSpan += timeSpan;
|
|
442
|
+
totalRealTimeSpan += realTimeSpan;
|
|
443
|
+
validSegments++;
|
|
444
|
+
}
|
|
445
|
+
}
|
|
446
|
+
if (validSegments > 0) {
|
|
447
|
+
this.averageSpeed = totalDistance / totalTimeSpan;
|
|
448
|
+
this.averageTimeInterval = totalRealTimeSpan / validSegments;
|
|
449
|
+
this.averageSpeed = Math.max(0.1, Math.min(this.averageSpeed, 1000));
|
|
450
|
+
this.averageTimeInterval = Math.max(0.01, Math.min(this.averageTimeInterval, 10));
|
|
451
|
+
}
|
|
452
|
+
}
|
|
453
|
+
calculateExpectedPosition(viewerTimeMs) {
|
|
454
|
+
const desired = this.calculateDesiredPosition(viewerTimeMs);
|
|
455
|
+
if (!desired.position) {
|
|
456
|
+
return { position: null, timeDelta: 0 };
|
|
457
|
+
}
|
|
458
|
+
let timeDelta = 0;
|
|
459
|
+
if (this.positionHistory.length >= 2) {
|
|
460
|
+
// Calculate how far behind we are based on viewer time vs real time.
|
|
461
|
+
const now = Date.now();
|
|
462
|
+
const timeDiffFromNow = (viewerTimeMs - now) / 1000.0;
|
|
463
|
+
// Negative means we're behind, positive means ahead.
|
|
464
|
+
timeDelta = timeDiffFromNow;
|
|
465
|
+
}
|
|
466
|
+
return { position: desired.position, timeDelta };
|
|
467
|
+
}
|
|
468
|
+
calculateAutonomousSpeed(distanceToTarget, timeDelta) {
|
|
469
|
+
let baseSpeed = this.averageSpeed || 50;
|
|
470
|
+
let speedMultiplier = 1.0;
|
|
471
|
+
// Calculate speed multiplier based on distance and time lag.
|
|
472
|
+
if (distanceToTarget > 50) {
|
|
473
|
+
speedMultiplier *= Math.min(100.0, distanceToTarget / 10.0);
|
|
474
|
+
}
|
|
475
|
+
else if (distanceToTarget > 10) {
|
|
476
|
+
const distanceMultiplier = Math.min(20.0, 1.0 + (distanceToTarget / 5.0));
|
|
477
|
+
speedMultiplier *= distanceMultiplier;
|
|
478
|
+
}
|
|
479
|
+
else if (Math.abs(timeDelta) > 0.1) {
|
|
480
|
+
const timeLagMultiplier = Math.max(0.1, 1.0 - (timeDelta * 5.0));
|
|
481
|
+
speedMultiplier *= Math.min(50.0, timeLagMultiplier);
|
|
482
|
+
}
|
|
483
|
+
// Minimum 10% speed.
|
|
484
|
+
return Math.max(baseSpeed * 0.1, baseSpeed * speedMultiplier);
|
|
485
|
+
}
|
|
431
486
|
sortPositions() {
|
|
432
487
|
if (this.positions.length > 0) {
|
|
433
488
|
this.positions.sort((a, b) => a.dateTime.getTime() - b.dateTime.getTime());
|
|
@@ -437,10 +492,6 @@ var CesiumAnimatedProperty;
|
|
|
437
492
|
this.lastCalcSeriesTime = null;
|
|
438
493
|
this.lastCalcOrientTime = null;
|
|
439
494
|
}
|
|
440
|
-
/**
|
|
441
|
-
* Pre-process headings in the series.
|
|
442
|
-
* If all are null or 0, then we assume all are null.
|
|
443
|
-
*/
|
|
444
495
|
processHeadings() {
|
|
445
496
|
if (!this.positions || this.positions.length === 0) {
|
|
446
497
|
return;
|
|
@@ -462,15 +513,10 @@ var CesiumAnimatedProperty;
|
|
|
462
513
|
easeInOutQuad(t) {
|
|
463
514
|
return t < 0.5 ? 2 * t * t : 1 - Math.pow(-2 * t + 2, 2) / 2;
|
|
464
515
|
}
|
|
465
|
-
/**
|
|
466
|
-
* Calculate the desired position based on current time without any animation smoothing.
|
|
467
|
-
*/
|
|
468
516
|
calculateDesiredPosition(timeMs) {
|
|
469
|
-
// No positions available
|
|
470
517
|
if (!this.positions || this.positions.length === 0) {
|
|
471
518
|
return { position: null, lastIndex: -1, nextIndex: -1 };
|
|
472
519
|
}
|
|
473
|
-
// Only one position.
|
|
474
520
|
if (this.positions.length === 1) {
|
|
475
521
|
return {
|
|
476
522
|
position: this.positions[0].pos3d || null,
|
|
@@ -478,7 +524,6 @@ var CesiumAnimatedProperty;
|
|
|
478
524
|
nextIndex: 0
|
|
479
525
|
};
|
|
480
526
|
}
|
|
481
|
-
// Before first position - use first two positions for orientation.
|
|
482
527
|
if (timeMs <= this.positions[0].dateTime.getTime()) {
|
|
483
528
|
return {
|
|
484
529
|
position: this.positions[0].pos3d || null,
|
|
@@ -486,7 +531,6 @@ var CesiumAnimatedProperty;
|
|
|
486
531
|
nextIndex: Math.min(1, this.positions.length - 1)
|
|
487
532
|
};
|
|
488
533
|
}
|
|
489
|
-
// After last position - use last two positions for orientation.
|
|
490
534
|
const lastIdx = this.positions.length - 1;
|
|
491
535
|
if (timeMs >= this.positions[lastIdx].dateTime.getTime()) {
|
|
492
536
|
return {
|
|
@@ -495,12 +539,10 @@ var CesiumAnimatedProperty;
|
|
|
495
539
|
nextIndex: lastIdx
|
|
496
540
|
};
|
|
497
541
|
}
|
|
498
|
-
// Find positions to interpolate between.
|
|
499
542
|
for (let i = 0; i < this.positions.length - 1; i++) {
|
|
500
543
|
const current = this.positions[i];
|
|
501
544
|
const next = this.positions[i + 1];
|
|
502
545
|
if (timeMs >= current.dateTime.getTime() && timeMs < next.dateTime.getTime()) {
|
|
503
|
-
// Exact match on current position - still use current and next for orientation.
|
|
504
546
|
if (timeMs === current.dateTime.getTime()) {
|
|
505
547
|
return {
|
|
506
548
|
position: current.pos3d || null,
|
|
@@ -508,7 +550,6 @@ var CesiumAnimatedProperty;
|
|
|
508
550
|
nextIndex: i + 1
|
|
509
551
|
};
|
|
510
552
|
}
|
|
511
|
-
// Interpolate between current and next.
|
|
512
553
|
if (!current.pos3d || !next.pos3d) {
|
|
513
554
|
return {
|
|
514
555
|
position: current.pos3d || next.pos3d || null,
|
|
@@ -535,99 +576,59 @@ var CesiumAnimatedProperty;
|
|
|
535
576
|
}
|
|
536
577
|
}
|
|
537
578
|
}
|
|
538
|
-
// Fallback to last position with previous position for orientation.
|
|
539
579
|
return {
|
|
540
580
|
position: this.positions[lastIdx].pos3d || null,
|
|
541
581
|
lastIndex: Math.max(0, lastIdx - 1),
|
|
542
582
|
nextIndex: lastIdx
|
|
543
583
|
};
|
|
544
584
|
}
|
|
545
|
-
/**
|
|
546
|
-
* Main method to get the current position based on time.
|
|
547
|
-
*/
|
|
548
585
|
GetValue() {
|
|
549
|
-
let
|
|
550
|
-
if (!
|
|
551
|
-
|
|
586
|
+
let viewerTime = this.viewer.scene.lastRenderTime;
|
|
587
|
+
if (!viewerTime) {
|
|
588
|
+
viewerTime = this.viewer.clock.currentTime;
|
|
552
589
|
}
|
|
553
|
-
const
|
|
590
|
+
const viewerTimeMs = Cesium.JulianDate.toDate(viewerTime).getTime();
|
|
554
591
|
const currentRealTimeMs = Date.now();
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
this.currentAnimatedPos = null;
|
|
560
|
-
this.currentTargetPos = null;
|
|
592
|
+
const expected = this.calculateExpectedPosition(viewerTimeMs);
|
|
593
|
+
if (!expected.position) {
|
|
594
|
+
this.currentPos = null;
|
|
595
|
+
this.currentVelocity = new Cesium.Cartesian3(0, 0, 0);
|
|
561
596
|
return new Cesium.Cartesian3();
|
|
562
597
|
}
|
|
563
|
-
|
|
598
|
+
const desired = this.calculateDesiredPosition(viewerTimeMs);
|
|
564
599
|
this.lastDesiredPosIndex = desired.lastIndex;
|
|
565
600
|
this.lastDesiredNextIndex = desired.nextIndex;
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
if (targetChanged) {
|
|
596
|
-
// Target changed mid-animation - start new animation from current position.
|
|
597
|
-
this.animationStartPos = this.currentAnimatedPos;
|
|
598
|
-
this.animationStartTime = currentRealTimeMs;
|
|
599
|
-
this.currentTargetPos = desired.position;
|
|
600
|
-
}
|
|
601
|
-
// Continue or start animation to target.
|
|
602
|
-
if (this.animationStartPos && this.animationStartTime) {
|
|
603
|
-
const progress = this.getAnimationProgress(currentRealTimeMs, this.animationStartTime);
|
|
604
|
-
// Animation complete.
|
|
605
|
-
if (progress >= 1.0) {
|
|
606
|
-
this.currentAnimatedPos = desired.position;
|
|
607
|
-
this.animationStartPos = null;
|
|
608
|
-
this.animationStartTime = null;
|
|
609
|
-
return desired.position;
|
|
610
|
-
}
|
|
611
|
-
// Continue animation.
|
|
612
|
-
else {
|
|
613
|
-
const easedProgress = this.easeInOutQuad(progress);
|
|
614
|
-
this.currentAnimatedPos = Cesium.Cartesian3.lerp(this.animationStartPos, desired.position, easedProgress, new Cesium.Cartesian3());
|
|
615
|
-
return this.currentAnimatedPos;
|
|
616
|
-
}
|
|
617
|
-
}
|
|
618
|
-
// No animation needed - already at target.
|
|
619
|
-
this.currentAnimatedPos = desired.position;
|
|
620
|
-
return desired.position;
|
|
621
|
-
}
|
|
622
|
-
getAnimationProgress(currentTime, startTime) {
|
|
623
|
-
const elapsed = currentTime - startTime;
|
|
624
|
-
return Math.min(elapsed / this.animationDuration, 1.0);
|
|
601
|
+
if (!this.currentPos) {
|
|
602
|
+
this.currentPos = expected.position.clone();
|
|
603
|
+
this.currentVelocity = new Cesium.Cartesian3(0, 0, 0);
|
|
604
|
+
this.lastUpdateTime = currentRealTimeMs;
|
|
605
|
+
return this.currentPos;
|
|
606
|
+
}
|
|
607
|
+
const deltaTime = this.lastUpdateTime ? (currentRealTimeMs - this.lastUpdateTime) / 1000.0 : 0.016;
|
|
608
|
+
this.lastUpdateTime = currentRealTimeMs;
|
|
609
|
+
const clampedDeltaTime = Math.min(deltaTime, 0.1);
|
|
610
|
+
const targetDistance = Cesium.Cartesian3.distance(this.currentPos, expected.position);
|
|
611
|
+
if (targetDistance < 0.5) {
|
|
612
|
+
this.currentPos = expected.position.clone();
|
|
613
|
+
this.currentVelocity = new Cesium.Cartesian3(0, 0, 0);
|
|
614
|
+
return this.currentPos;
|
|
615
|
+
}
|
|
616
|
+
// Check if we're really far behind and need to teleport.
|
|
617
|
+
if (targetDistance > 500) {
|
|
618
|
+
this.currentPos = expected.position.clone();
|
|
619
|
+
this.currentVelocity = new Cesium.Cartesian3(0, 0, 0);
|
|
620
|
+
return this.currentPos;
|
|
621
|
+
}
|
|
622
|
+
const direction = Cesium.Cartesian3.subtract(expected.position, this.currentPos, new Cesium.Cartesian3());
|
|
623
|
+
Cesium.Cartesian3.normalize(direction, direction);
|
|
624
|
+
const targetSpeed = this.calculateAutonomousSpeed(targetDistance, expected.timeDelta);
|
|
625
|
+
const targetVelocity = Cesium.Cartesian3.multiplyByScalar(direction, targetSpeed, new Cesium.Cartesian3());
|
|
626
|
+
this.currentVelocity = Cesium.Cartesian3.lerp(this.currentVelocity, targetVelocity, this.smoothingFactor, new Cesium.Cartesian3());
|
|
627
|
+
const velocityDelta = Cesium.Cartesian3.multiplyByScalar(this.currentVelocity, clampedDeltaTime, new Cesium.Cartesian3());
|
|
628
|
+
this.currentPos = Cesium.Cartesian3.add(this.currentPos, velocityDelta, new Cesium.Cartesian3());
|
|
629
|
+
return this.currentPos;
|
|
625
630
|
}
|
|
626
|
-
/**
|
|
627
|
-
* Returns a series of positions to use for rendering the path.
|
|
628
|
-
*/
|
|
629
631
|
GetSeries() {
|
|
630
|
-
// Update at 30 fps.
|
|
631
632
|
let doUpdate = this.lastCalcSeriesTime == null;
|
|
632
633
|
if (!doUpdate && this.lastCalcSeriesTime && (new Date().getTime() - this.lastCalcSeriesTime) > 1000 / 30) {
|
|
633
634
|
doUpdate = true;
|
|
@@ -635,33 +636,27 @@ var CesiumAnimatedProperty;
|
|
|
635
636
|
if (!doUpdate) {
|
|
636
637
|
return this.lastCalcSeriesPos3d;
|
|
637
638
|
}
|
|
638
|
-
// Ensure position indices are up-to-date.
|
|
639
639
|
this.GetValue();
|
|
640
640
|
let now = this.viewer.scene.lastRenderTime;
|
|
641
641
|
if (!now) {
|
|
642
642
|
now = this.viewer.clock.currentTime;
|
|
643
643
|
}
|
|
644
644
|
const nowDate = Cesium.JulianDate.toDate(now);
|
|
645
|
-
// Get total duration.
|
|
646
645
|
if (!this.positions || this.positions.length < 2) {
|
|
647
646
|
this.lastCalcSeriesTime = nowDate.getTime();
|
|
648
647
|
this.lastCalcSeriesPos3d = [];
|
|
649
648
|
return [];
|
|
650
649
|
}
|
|
651
|
-
const totalDuration = this.positions[this.positions.length - 1].dateTime.getTime() -
|
|
652
|
-
|
|
653
|
-
// Percentage of the polyline to be visible before and after each point.
|
|
654
|
-
const visibilityPercentage = 0.05; // 5%
|
|
650
|
+
const totalDuration = this.positions[this.positions.length - 1].dateTime.getTime() - this.positions[0].dateTime.getTime();
|
|
651
|
+
const visibilityPercentage = 0.05;
|
|
655
652
|
const visibilityDuration = totalDuration * visibilityPercentage;
|
|
656
|
-
// Gather positions that fall within the visibility duration.
|
|
657
653
|
const newPosses = [];
|
|
658
654
|
for (let i = 0; i < this.positions.length; i++) {
|
|
659
655
|
const pos = this.positions[i];
|
|
660
|
-
if (!pos.pos3d)
|
|
656
|
+
if (!pos.pos3d) {
|
|
661
657
|
continue;
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
// Also include the segment we're currently traversing.
|
|
658
|
+
}
|
|
659
|
+
let add = nowDate >= new Date(pos.dateTime.getTime() - visibilityDuration / 2) && nowDate <= new Date(pos.dateTime.getTime() + visibilityDuration / 2);
|
|
665
660
|
if (!add && this.lastDesiredPosIndex > -1 && this.lastDesiredNextIndex > -1) {
|
|
666
661
|
add = i >= this.lastDesiredPosIndex && i <= this.lastDesiredNextIndex;
|
|
667
662
|
}
|
|
@@ -673,11 +668,7 @@ var CesiumAnimatedProperty;
|
|
|
673
668
|
this.lastCalcSeriesPos3d = newPosses;
|
|
674
669
|
return newPosses;
|
|
675
670
|
}
|
|
676
|
-
/**
|
|
677
|
-
* Returns the orientation based on current position and heading.
|
|
678
|
-
*/
|
|
679
671
|
GetOrient() {
|
|
680
|
-
// Update at 30 fps.
|
|
681
672
|
let doUpdate = this.lastCalcOrientTime == null;
|
|
682
673
|
if (!doUpdate && this.lastCalcOrientTime && (new Date().getTime() - this.lastCalcOrientTime) > 1000 / 30) {
|
|
683
674
|
doUpdate = true;
|
|
@@ -685,26 +676,34 @@ var CesiumAnimatedProperty;
|
|
|
685
676
|
if (!doUpdate && this.lastCalcOrient) {
|
|
686
677
|
return this.lastCalcOrient;
|
|
687
678
|
}
|
|
688
|
-
// Default quaternion to return if we can't calculate.
|
|
689
679
|
const defaultQuaternion = new Cesium.Quaternion();
|
|
690
680
|
if (!this.positions || this.positions.length === 0) {
|
|
691
681
|
return defaultQuaternion;
|
|
692
682
|
}
|
|
693
|
-
// Ensure position is up-to-date.
|
|
694
683
|
const currentPosition = this.GetValue();
|
|
695
684
|
if (!currentPosition) {
|
|
696
685
|
return defaultQuaternion;
|
|
697
686
|
}
|
|
698
|
-
let now = this.viewer.scene.lastRenderTime;
|
|
699
|
-
if (!now) {
|
|
700
|
-
now = this.viewer.clock.currentTime;
|
|
701
|
-
}
|
|
702
|
-
const nowTime = Cesium.JulianDate.toDate(now).getTime();
|
|
703
687
|
try {
|
|
704
|
-
|
|
688
|
+
const velocityMagnitude = Cesium.Cartesian3.magnitude(this.currentVelocity);
|
|
689
|
+
const minimumSpeedForVelocityOrientation = Math.max(1.0, this.averageSpeed * 0.1);
|
|
690
|
+
if (velocityMagnitude > minimumSpeedForVelocityOrientation) {
|
|
691
|
+
const normalizedVelocity = Cesium.Cartesian3.normalize(this.currentVelocity, new Cesium.Cartesian3());
|
|
692
|
+
const rotationMatrix = Cesium.Transforms.rotationMatrixFromPositionVelocity(currentPosition, normalizedVelocity);
|
|
693
|
+
const quaternion = Cesium.Quaternion.fromRotationMatrix(rotationMatrix);
|
|
694
|
+
const hpr = new Cesium.HeadingPitchRoll(0, Cesium.Math.toRadians(this.pitch), Cesium.Math.toRadians(this.roll));
|
|
695
|
+
const pitchRollQuaternion = Cesium.Quaternion.fromHeadingPitchRoll(hpr);
|
|
696
|
+
this.lastCalcOrient = Cesium.Quaternion.multiply(quaternion, pitchRollQuaternion, new Cesium.Quaternion());
|
|
697
|
+
this.lastCalcOrientTime = Date.now();
|
|
698
|
+
return this.lastCalcOrient;
|
|
699
|
+
}
|
|
700
|
+
let now = this.viewer.scene.lastRenderTime;
|
|
701
|
+
if (!now) {
|
|
702
|
+
now = this.viewer.clock.currentTime;
|
|
703
|
+
}
|
|
704
|
+
const nowTime = Cesium.JulianDate.toDate(now).getTime();
|
|
705
705
|
const lastIndex = this.lastDesiredPosIndex;
|
|
706
706
|
const nextIndex = this.lastDesiredNextIndex;
|
|
707
|
-
// Invalid indices.
|
|
708
707
|
if (lastIndex < 0 || nextIndex < 0 ||
|
|
709
708
|
lastIndex >= this.positions.length || nextIndex >= this.positions.length) {
|
|
710
709
|
return this.lastCalcOrient || defaultQuaternion;
|
|
@@ -714,74 +713,53 @@ var CesiumAnimatedProperty;
|
|
|
714
713
|
if (!lastPos || !nextPos) {
|
|
715
714
|
return this.lastCalcOrient || defaultQuaternion;
|
|
716
715
|
}
|
|
717
|
-
// Single position case - use its heading if available.
|
|
718
716
|
if (lastIndex === nextIndex) {
|
|
719
717
|
if (lastPos.heading !== null) {
|
|
720
718
|
this.lastCalcOrient = Cesium.Transforms.headingPitchRollQuaternion(currentPosition, new Cesium.HeadingPitchRoll(Cesium.Math.toRadians(lastPos.heading), Cesium.Math.toRadians(this.pitch), Cesium.Math.toRadians(this.roll)));
|
|
721
719
|
this.lastCalcOrientTime = Date.now();
|
|
722
720
|
return this.lastCalcOrient;
|
|
723
721
|
}
|
|
724
|
-
// No heading data and single position, return previous or default.
|
|
725
722
|
return this.lastCalcOrient || defaultQuaternion;
|
|
726
723
|
}
|
|
727
|
-
// Two different positions - we can calculate orientation.
|
|
728
|
-
// Use explicit heading values if available.
|
|
729
724
|
if (lastPos.heading !== null && nextPos.heading !== null) {
|
|
730
|
-
// Calculate interpolated heading.
|
|
731
725
|
let deltaHeading = nextPos.heading - lastPos.heading;
|
|
732
|
-
// Handle wrap-around between 359° and 0°.
|
|
733
726
|
if (deltaHeading > 180) {
|
|
734
727
|
deltaHeading -= 360;
|
|
735
728
|
}
|
|
736
729
|
else if (deltaHeading < -180) {
|
|
737
730
|
deltaHeading += 360;
|
|
738
731
|
}
|
|
739
|
-
// Calculate interpolation factor.
|
|
740
732
|
let factor = 0;
|
|
741
733
|
if (lastPos.dateTime.getTime() !== nextPos.dateTime.getTime()) {
|
|
742
|
-
factor = (nowTime - lastPos.dateTime.getTime()) /
|
|
743
|
-
(nextPos.dateTime.getTime() - lastPos.dateTime.getTime());
|
|
734
|
+
factor = (nowTime - lastPos.dateTime.getTime()) / (nextPos.dateTime.getTime() - lastPos.dateTime.getTime());
|
|
744
735
|
factor = Math.max(0, Math.min(1, factor));
|
|
745
736
|
}
|
|
746
|
-
// Apply easing for smoother rotation.
|
|
747
737
|
factor = this.easeInOutQuad(factor);
|
|
748
|
-
// Calculate final heading.
|
|
749
738
|
let interpolatedHeading = lastPos.heading + factor * deltaHeading;
|
|
750
739
|
interpolatedHeading = (interpolatedHeading + 360) % 360;
|
|
751
|
-
// Create quaternion from heading, pitch, roll.
|
|
752
740
|
this.lastCalcOrient = Cesium.Transforms.headingPitchRollQuaternion(currentPosition, new Cesium.HeadingPitchRoll(Cesium.Math.toRadians(interpolatedHeading), Cesium.Math.toRadians(this.pitch), Cesium.Math.toRadians(this.roll)));
|
|
753
741
|
}
|
|
754
|
-
// Calculate heading from position changes if heading data not available.
|
|
755
742
|
else {
|
|
756
743
|
if (!lastPos.pos3d || !nextPos.pos3d) {
|
|
757
744
|
return this.lastCalcOrient || defaultQuaternion;
|
|
758
745
|
}
|
|
759
|
-
// Flatten positions to avoid altitude-related heading changes.
|
|
760
746
|
const adjustedPointPrev = Cesium.Cartographic.fromCartesian(lastPos.pos3d);
|
|
761
747
|
const adjustedPos3dPrev = Cesium.Cartesian3.fromRadians(adjustedPointPrev.longitude, adjustedPointPrev.latitude, 0);
|
|
762
748
|
const adjustedPointNext = Cesium.Cartographic.fromCartesian(nextPos.pos3d);
|
|
763
749
|
const adjustedPos3dNext = Cesium.Cartesian3.fromRadians(adjustedPointNext.longitude, adjustedPointNext.latitude, 0);
|
|
764
|
-
// Skip if positions are too close (less than 5cm).
|
|
765
750
|
const distance = Cesium.Cartesian3.distance(adjustedPos3dPrev, adjustedPos3dNext);
|
|
766
751
|
if (distance < 0.05) {
|
|
767
752
|
return this.lastCalcOrient || defaultQuaternion;
|
|
768
753
|
}
|
|
769
|
-
// Calculate direction vector.
|
|
770
754
|
const direction = Cesium.Cartesian3.subtract(adjustedPos3dNext, adjustedPos3dPrev, new Cesium.Cartesian3());
|
|
771
|
-
// Skip if no movement.
|
|
772
755
|
if (direction.x === 0 && direction.y === 0 && direction.z === 0) {
|
|
773
756
|
return this.lastCalcOrient || defaultQuaternion;
|
|
774
757
|
}
|
|
775
|
-
// Normalize the direction vector.
|
|
776
758
|
Cesium.Cartesian3.normalize(direction, direction);
|
|
777
|
-
// Calculate rotation based on movement direction.
|
|
778
759
|
const rotationMatrix = Cesium.Transforms.rotationMatrixFromPositionVelocity(currentPosition, direction);
|
|
779
|
-
// Convert to quaternion.
|
|
780
760
|
const quaternion = Cesium.Quaternion.fromRotationMatrix(rotationMatrix);
|
|
781
|
-
// Add pitch and roll adjustments.
|
|
782
761
|
const hpr = new Cesium.HeadingPitchRoll(0, Cesium.Math.toRadians(this.pitch), Cesium.Math.toRadians(this.roll));
|
|
783
762
|
const pitchRollQuaternion = Cesium.Quaternion.fromHeadingPitchRoll(hpr);
|
|
784
|
-
// Combine quaternions.
|
|
785
763
|
this.lastCalcOrient = Cesium.Quaternion.multiply(quaternion, pitchRollQuaternion, new Cesium.Quaternion());
|
|
786
764
|
}
|
|
787
765
|
}
|
|
@@ -792,6 +770,52 @@ var CesiumAnimatedProperty;
|
|
|
792
770
|
this.lastCalcOrientTime = Date.now();
|
|
793
771
|
return this.lastCalcOrient;
|
|
794
772
|
}
|
|
773
|
+
GetCurrentVelocity() {
|
|
774
|
+
return this.currentVelocity ? this.currentVelocity.clone() : new Cesium.Cartesian3(0, 0, 0);
|
|
775
|
+
}
|
|
776
|
+
SupplementSeries(newSeries) {
|
|
777
|
+
if (!newSeries || newSeries.length === 0) {
|
|
778
|
+
return;
|
|
779
|
+
}
|
|
780
|
+
for (const pos of newSeries) {
|
|
781
|
+
if (!pos || !pos.pos3d || !pos.dateTime) {
|
|
782
|
+
continue;
|
|
783
|
+
}
|
|
784
|
+
const existingIndex = this.positions.findIndex(p => p.dateTime.getTime() === pos.dateTime.getTime());
|
|
785
|
+
if (existingIndex >= 0) {
|
|
786
|
+
this.positions[existingIndex] = pos;
|
|
787
|
+
}
|
|
788
|
+
else {
|
|
789
|
+
this.AddPosition(pos);
|
|
790
|
+
}
|
|
791
|
+
}
|
|
792
|
+
}
|
|
793
|
+
UpdatePositionForDateTime(pos3d, dateTime, heading) {
|
|
794
|
+
if (!pos3d || !dateTime) {
|
|
795
|
+
return;
|
|
796
|
+
}
|
|
797
|
+
const existingIndex = this.positions.findIndex(p => p.dateTime.getTime() === dateTime.getTime());
|
|
798
|
+
const newPos = {
|
|
799
|
+
pos3d: pos3d,
|
|
800
|
+
dateTime: dateTime,
|
|
801
|
+
heading: heading !== undefined ? heading : null
|
|
802
|
+
};
|
|
803
|
+
if (existingIndex >= 0) {
|
|
804
|
+
this.positions[existingIndex] = newPos;
|
|
805
|
+
this.processHeadings();
|
|
806
|
+
this.sortPositions();
|
|
807
|
+
this.invalidateCache();
|
|
808
|
+
}
|
|
809
|
+
else {
|
|
810
|
+
this.AddPosition(newPos);
|
|
811
|
+
}
|
|
812
|
+
}
|
|
813
|
+
HasPositionForDateTime(dateTime) {
|
|
814
|
+
return this.positions.some(p => p.dateTime.getTime() === dateTime.getTime());
|
|
815
|
+
}
|
|
816
|
+
GetPositionCount() {
|
|
817
|
+
return this.positions.length;
|
|
818
|
+
}
|
|
795
819
|
}
|
|
796
820
|
CesiumAnimatedProperty.AnimatePositionSeries = AnimatePositionSeries;
|
|
797
821
|
function GetSeriesPossesForHistoricEntity(viewer, dataHeightRef, heightRef, historic) {
|