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.
@@ -1142,19 +1142,18 @@
1142
1142
  */
1143
1143
  class AnimatePositionSeries {
1144
1144
  constructor(params) {
1145
- // Animation state.
1146
- this.currentAnimatedPos = null;
1147
- this.currentTargetPos = null;
1148
- this.animationStartPos = null;
1149
- this.animationStartTime = null;
1150
- this.animationDuration = 200;
1151
- // Cached data for performance.
1145
+ this.currentPos = null;
1146
+ this.currentVelocity = new Cesium.Cartesian3(0, 0, 0);
1147
+ this.smoothingFactor = 0.5;
1148
+ this.positionHistory = [];
1149
+ this.maxHistorySize = 10;
1150
+ this.averageSpeed = 0;
1151
+ this.averageTimeInterval = 0;
1152
+ this.lastUpdateTime = null;
1152
1153
  this.lastDesiredPosIndex = -1;
1153
1154
  this.lastDesiredNextIndex = -1;
1154
- // Series data for rendering path
1155
1155
  this.lastCalcSeriesPos3d = [];
1156
1156
  this.lastCalcSeriesTime = null;
1157
- // Orientation cache.
1158
1157
  this.lastCalcOrient = null;
1159
1158
  this.lastCalcOrientTime = null;
1160
1159
  this.viewer = params.viewer;
@@ -1163,25 +1162,23 @@
1163
1162
  this.roll = params.roll || 0;
1164
1163
  this.processHeadings();
1165
1164
  this.sortPositions();
1166
- // Initialize animation from starting position if provided.
1167
- if (params.animateFromPos3d) {
1168
- this.animationStartPos = params.animateFromPos3d;
1169
- const currentTime = Date.now();
1170
- const providedTime = params.animateFromPos3dTimeStart || 0;
1171
- // Check if the provided timestamp is stale.
1172
- if (!providedTime || (currentTime - providedTime) >= this.animationDuration) {
1173
- this.animationStartTime = currentTime;
1174
- }
1175
- else {
1176
- this.animationStartTime = providedTime;
1177
- }
1178
- }
1179
1165
  }
1180
1166
  AddPosition(pos) {
1181
1167
  if (!pos || !pos.pos3d || !pos.dateTime) {
1182
1168
  console.warn("Invalid position provided to AnimatePositionSeries.");
1183
1169
  return;
1184
1170
  }
1171
+ const now = Date.now();
1172
+ const posTime = pos.dateTime.getTime();
1173
+ this.positionHistory.push({
1174
+ pos: pos.pos3d.clone(),
1175
+ time: posTime,
1176
+ realTime: now
1177
+ });
1178
+ if (this.positionHistory.length > this.maxHistorySize) {
1179
+ this.positionHistory.shift();
1180
+ }
1181
+ this.analyzeMovementPatterns();
1185
1182
  this.positions.push(pos);
1186
1183
  this.processHeadings();
1187
1184
  this.sortPositions();
@@ -1192,12 +1189,70 @@
1192
1189
  this.roll = roll;
1193
1190
  this.invalidateCache();
1194
1191
  }
1195
- GetAnimateFromDateTime() {
1196
- return this.animationStartTime;
1197
- }
1198
1192
  GetPositions() {
1199
1193
  return this.positions;
1200
1194
  }
1195
+ analyzeMovementPatterns() {
1196
+ if (this.positionHistory.length < 2) {
1197
+ return;
1198
+ }
1199
+ let totalDistance = 0;
1200
+ let totalTimeSpan = 0;
1201
+ let totalRealTimeSpan = 0;
1202
+ let validSegments = 0;
1203
+ for (let i = 1; i < this.positionHistory.length; i++) {
1204
+ const prev = this.positionHistory[i - 1];
1205
+ const curr = this.positionHistory[i];
1206
+ const distance = Cesium.Cartesian3.distance(prev.pos, curr.pos);
1207
+ const timeSpan = Math.abs(curr.time - prev.time) / 1000.0;
1208
+ const realTimeSpan = Math.abs(curr.realTime - prev.realTime) / 1000.0;
1209
+ if (distance > 0.1 && timeSpan > 0.01) {
1210
+ totalDistance += distance;
1211
+ totalTimeSpan += timeSpan;
1212
+ totalRealTimeSpan += realTimeSpan;
1213
+ validSegments++;
1214
+ }
1215
+ }
1216
+ if (validSegments > 0) {
1217
+ this.averageSpeed = totalDistance / totalTimeSpan;
1218
+ this.averageTimeInterval = totalRealTimeSpan / validSegments;
1219
+ this.averageSpeed = Math.max(0.1, Math.min(this.averageSpeed, 1000));
1220
+ this.averageTimeInterval = Math.max(0.01, Math.min(this.averageTimeInterval, 10));
1221
+ }
1222
+ }
1223
+ calculateExpectedPosition(viewerTimeMs) {
1224
+ const desired = this.calculateDesiredPosition(viewerTimeMs);
1225
+ if (!desired.position) {
1226
+ return { position: null, timeDelta: 0 };
1227
+ }
1228
+ let timeDelta = 0;
1229
+ if (this.positionHistory.length >= 2) {
1230
+ // Calculate how far behind we are based on viewer time vs real time.
1231
+ const now = Date.now();
1232
+ const timeDiffFromNow = (viewerTimeMs - now) / 1000.0;
1233
+ // Negative means we're behind, positive means ahead.
1234
+ timeDelta = timeDiffFromNow;
1235
+ }
1236
+ return { position: desired.position, timeDelta };
1237
+ }
1238
+ calculateAutonomousSpeed(distanceToTarget, timeDelta) {
1239
+ let baseSpeed = this.averageSpeed || 50;
1240
+ let speedMultiplier = 1.0;
1241
+ // Calculate speed multiplier based on distance and time lag.
1242
+ if (distanceToTarget > 50) {
1243
+ speedMultiplier *= Math.min(100.0, distanceToTarget / 10.0);
1244
+ }
1245
+ else if (distanceToTarget > 10) {
1246
+ const distanceMultiplier = Math.min(20.0, 1.0 + (distanceToTarget / 5.0));
1247
+ speedMultiplier *= distanceMultiplier;
1248
+ }
1249
+ else if (Math.abs(timeDelta) > 0.1) {
1250
+ const timeLagMultiplier = Math.max(0.1, 1.0 - (timeDelta * 5.0));
1251
+ speedMultiplier *= Math.min(50.0, timeLagMultiplier);
1252
+ }
1253
+ // Minimum 10% speed.
1254
+ return Math.max(baseSpeed * 0.1, baseSpeed * speedMultiplier);
1255
+ }
1201
1256
  sortPositions() {
1202
1257
  if (this.positions.length > 0) {
1203
1258
  this.positions.sort((a, b) => a.dateTime.getTime() - b.dateTime.getTime());
@@ -1207,10 +1262,6 @@
1207
1262
  this.lastCalcSeriesTime = null;
1208
1263
  this.lastCalcOrientTime = null;
1209
1264
  }
1210
- /**
1211
- * Pre-process headings in the series.
1212
- * If all are null or 0, then we assume all are null.
1213
- */
1214
1265
  processHeadings() {
1215
1266
  if (!this.positions || this.positions.length === 0) {
1216
1267
  return;
@@ -1232,15 +1283,10 @@
1232
1283
  easeInOutQuad(t) {
1233
1284
  return t < 0.5 ? 2 * t * t : 1 - Math.pow(-2 * t + 2, 2) / 2;
1234
1285
  }
1235
- /**
1236
- * Calculate the desired position based on current time without any animation smoothing.
1237
- */
1238
1286
  calculateDesiredPosition(timeMs) {
1239
- // No positions available
1240
1287
  if (!this.positions || this.positions.length === 0) {
1241
1288
  return { position: null, lastIndex: -1, nextIndex: -1 };
1242
1289
  }
1243
- // Only one position.
1244
1290
  if (this.positions.length === 1) {
1245
1291
  return {
1246
1292
  position: this.positions[0].pos3d || null,
@@ -1248,7 +1294,6 @@
1248
1294
  nextIndex: 0
1249
1295
  };
1250
1296
  }
1251
- // Before first position - use first two positions for orientation.
1252
1297
  if (timeMs <= this.positions[0].dateTime.getTime()) {
1253
1298
  return {
1254
1299
  position: this.positions[0].pos3d || null,
@@ -1256,7 +1301,6 @@
1256
1301
  nextIndex: Math.min(1, this.positions.length - 1)
1257
1302
  };
1258
1303
  }
1259
- // After last position - use last two positions for orientation.
1260
1304
  const lastIdx = this.positions.length - 1;
1261
1305
  if (timeMs >= this.positions[lastIdx].dateTime.getTime()) {
1262
1306
  return {
@@ -1265,12 +1309,10 @@
1265
1309
  nextIndex: lastIdx
1266
1310
  };
1267
1311
  }
1268
- // Find positions to interpolate between.
1269
1312
  for (let i = 0; i < this.positions.length - 1; i++) {
1270
1313
  const current = this.positions[i];
1271
1314
  const next = this.positions[i + 1];
1272
1315
  if (timeMs >= current.dateTime.getTime() && timeMs < next.dateTime.getTime()) {
1273
- // Exact match on current position - still use current and next for orientation.
1274
1316
  if (timeMs === current.dateTime.getTime()) {
1275
1317
  return {
1276
1318
  position: current.pos3d || null,
@@ -1278,7 +1320,6 @@
1278
1320
  nextIndex: i + 1
1279
1321
  };
1280
1322
  }
1281
- // Interpolate between current and next.
1282
1323
  if (!current.pos3d || !next.pos3d) {
1283
1324
  return {
1284
1325
  position: current.pos3d || next.pos3d || null,
@@ -1305,99 +1346,59 @@
1305
1346
  }
1306
1347
  }
1307
1348
  }
1308
- // Fallback to last position with previous position for orientation.
1309
1349
  return {
1310
1350
  position: this.positions[lastIdx].pos3d || null,
1311
1351
  lastIndex: Math.max(0, lastIdx - 1),
1312
1352
  nextIndex: lastIdx
1313
1353
  };
1314
1354
  }
1315
- /**
1316
- * Main method to get the current position based on time.
1317
- */
1318
1355
  GetValue() {
1319
- let now = this.viewer.scene.lastRenderTime;
1320
- if (!now) {
1321
- now = this.viewer.clock.currentTime;
1356
+ let viewerTime = this.viewer.scene.lastRenderTime;
1357
+ if (!viewerTime) {
1358
+ viewerTime = this.viewer.clock.currentTime;
1322
1359
  }
1323
- const nowTimeMs = Cesium.JulianDate.toDate(now).getTime();
1360
+ const viewerTimeMs = Cesium.JulianDate.toDate(viewerTime).getTime();
1324
1361
  const currentRealTimeMs = Date.now();
1325
- // Calculate the desired position based on time.
1326
- const desired = this.calculateDesiredPosition(nowTimeMs);
1327
- // If no desired position, return empty position.
1328
- if (!desired.position) {
1329
- this.currentAnimatedPos = null;
1330
- this.currentTargetPos = null;
1362
+ const expected = this.calculateExpectedPosition(viewerTimeMs);
1363
+ if (!expected.position) {
1364
+ this.currentPos = null;
1365
+ this.currentVelocity = new Cesium.Cartesian3(0, 0, 0);
1331
1366
  return new Cesium.Cartesian3();
1332
1367
  }
1333
- // Cache the desired position info for orientation calculations.
1368
+ const desired = this.calculateDesiredPosition(viewerTimeMs);
1334
1369
  this.lastDesiredPosIndex = desired.lastIndex;
1335
1370
  this.lastDesiredNextIndex = desired.nextIndex;
1336
- // First time or no previous position - start here.
1337
- if (!this.currentAnimatedPos) {
1338
- // If we have a starting animation position, animate from it.
1339
- if (this.animationStartPos) {
1340
- this.currentTargetPos = desired.position;
1341
- const progress = this.getAnimationProgress(currentRealTimeMs, this.animationStartTime);
1342
- if (progress >= 1.0) {
1343
- // Animation complete.
1344
- this.currentAnimatedPos = desired.position;
1345
- this.animationStartPos = null;
1346
- this.animationStartTime = null;
1347
- return desired.position;
1348
- }
1349
- else {
1350
- // Continue animation.
1351
- const easedProgress = this.easeInOutQuad(progress);
1352
- this.currentAnimatedPos = Cesium.Cartesian3.lerp(this.animationStartPos, desired.position, easedProgress, new Cesium.Cartesian3());
1353
- return this.currentAnimatedPos;
1354
- }
1355
- }
1356
- else {
1357
- // No animation, start at desired position.
1358
- this.currentAnimatedPos = desired.position;
1359
- this.currentTargetPos = desired.position;
1360
- return desired.position;
1361
- }
1362
- }
1363
- // Check if target has changed.
1364
- const targetChanged = !this.currentTargetPos || !Cesium.Cartesian3.equals(this.currentTargetPos, desired.position);
1365
- if (targetChanged) {
1366
- // Target changed mid-animation - start new animation from current position.
1367
- this.animationStartPos = this.currentAnimatedPos;
1368
- this.animationStartTime = currentRealTimeMs;
1369
- this.currentTargetPos = desired.position;
1370
- }
1371
- // Continue or start animation to target.
1372
- if (this.animationStartPos && this.animationStartTime) {
1373
- const progress = this.getAnimationProgress(currentRealTimeMs, this.animationStartTime);
1374
- // Animation complete.
1375
- if (progress >= 1.0) {
1376
- this.currentAnimatedPos = desired.position;
1377
- this.animationStartPos = null;
1378
- this.animationStartTime = null;
1379
- return desired.position;
1380
- }
1381
- // Continue animation.
1382
- else {
1383
- const easedProgress = this.easeInOutQuad(progress);
1384
- this.currentAnimatedPos = Cesium.Cartesian3.lerp(this.animationStartPos, desired.position, easedProgress, new Cesium.Cartesian3());
1385
- return this.currentAnimatedPos;
1386
- }
1387
- }
1388
- // No animation needed - already at target.
1389
- this.currentAnimatedPos = desired.position;
1390
- return desired.position;
1391
- }
1392
- getAnimationProgress(currentTime, startTime) {
1393
- const elapsed = currentTime - startTime;
1394
- return Math.min(elapsed / this.animationDuration, 1.0);
1371
+ if (!this.currentPos) {
1372
+ this.currentPos = expected.position.clone();
1373
+ this.currentVelocity = new Cesium.Cartesian3(0, 0, 0);
1374
+ this.lastUpdateTime = currentRealTimeMs;
1375
+ return this.currentPos;
1376
+ }
1377
+ const deltaTime = this.lastUpdateTime ? (currentRealTimeMs - this.lastUpdateTime) / 1000.0 : 0.016;
1378
+ this.lastUpdateTime = currentRealTimeMs;
1379
+ const clampedDeltaTime = Math.min(deltaTime, 0.1);
1380
+ const targetDistance = Cesium.Cartesian3.distance(this.currentPos, expected.position);
1381
+ if (targetDistance < 0.5) {
1382
+ this.currentPos = expected.position.clone();
1383
+ this.currentVelocity = new Cesium.Cartesian3(0, 0, 0);
1384
+ return this.currentPos;
1385
+ }
1386
+ // Check if we're really far behind and need to teleport.
1387
+ if (targetDistance > 500) {
1388
+ this.currentPos = expected.position.clone();
1389
+ this.currentVelocity = new Cesium.Cartesian3(0, 0, 0);
1390
+ return this.currentPos;
1391
+ }
1392
+ const direction = Cesium.Cartesian3.subtract(expected.position, this.currentPos, new Cesium.Cartesian3());
1393
+ Cesium.Cartesian3.normalize(direction, direction);
1394
+ const targetSpeed = this.calculateAutonomousSpeed(targetDistance, expected.timeDelta);
1395
+ const targetVelocity = Cesium.Cartesian3.multiplyByScalar(direction, targetSpeed, new Cesium.Cartesian3());
1396
+ this.currentVelocity = Cesium.Cartesian3.lerp(this.currentVelocity, targetVelocity, this.smoothingFactor, new Cesium.Cartesian3());
1397
+ const velocityDelta = Cesium.Cartesian3.multiplyByScalar(this.currentVelocity, clampedDeltaTime, new Cesium.Cartesian3());
1398
+ this.currentPos = Cesium.Cartesian3.add(this.currentPos, velocityDelta, new Cesium.Cartesian3());
1399
+ return this.currentPos;
1395
1400
  }
1396
- /**
1397
- * Returns a series of positions to use for rendering the path.
1398
- */
1399
1401
  GetSeries() {
1400
- // Update at 30 fps.
1401
1402
  let doUpdate = this.lastCalcSeriesTime == null;
1402
1403
  if (!doUpdate && this.lastCalcSeriesTime && (new Date().getTime() - this.lastCalcSeriesTime) > 1000 / 30) {
1403
1404
  doUpdate = true;
@@ -1405,33 +1406,27 @@
1405
1406
  if (!doUpdate) {
1406
1407
  return this.lastCalcSeriesPos3d;
1407
1408
  }
1408
- // Ensure position indices are up-to-date.
1409
1409
  this.GetValue();
1410
1410
  let now = this.viewer.scene.lastRenderTime;
1411
1411
  if (!now) {
1412
1412
  now = this.viewer.clock.currentTime;
1413
1413
  }
1414
1414
  const nowDate = Cesium.JulianDate.toDate(now);
1415
- // Get total duration.
1416
1415
  if (!this.positions || this.positions.length < 2) {
1417
1416
  this.lastCalcSeriesTime = nowDate.getTime();
1418
1417
  this.lastCalcSeriesPos3d = [];
1419
1418
  return [];
1420
1419
  }
1421
- const totalDuration = this.positions[this.positions.length - 1].dateTime.getTime() -
1422
- this.positions[0].dateTime.getTime();
1423
- // Percentage of the polyline to be visible before and after each point.
1424
- const visibilityPercentage = 0.05; // 5%
1420
+ const totalDuration = this.positions[this.positions.length - 1].dateTime.getTime() - this.positions[0].dateTime.getTime();
1421
+ const visibilityPercentage = 0.05;
1425
1422
  const visibilityDuration = totalDuration * visibilityPercentage;
1426
- // Gather positions that fall within the visibility duration.
1427
1423
  const newPosses = [];
1428
1424
  for (let i = 0; i < this.positions.length; i++) {
1429
1425
  const pos = this.positions[i];
1430
- if (!pos.pos3d)
1426
+ if (!pos.pos3d) {
1431
1427
  continue;
1432
- let add = nowDate >= new Date(pos.dateTime.getTime() - visibilityDuration / 2) &&
1433
- nowDate <= new Date(pos.dateTime.getTime() + visibilityDuration / 2);
1434
- // Also include the segment we're currently traversing.
1428
+ }
1429
+ let add = nowDate >= new Date(pos.dateTime.getTime() - visibilityDuration / 2) && nowDate <= new Date(pos.dateTime.getTime() + visibilityDuration / 2);
1435
1430
  if (!add && this.lastDesiredPosIndex > -1 && this.lastDesiredNextIndex > -1) {
1436
1431
  add = i >= this.lastDesiredPosIndex && i <= this.lastDesiredNextIndex;
1437
1432
  }
@@ -1443,11 +1438,7 @@
1443
1438
  this.lastCalcSeriesPos3d = newPosses;
1444
1439
  return newPosses;
1445
1440
  }
1446
- /**
1447
- * Returns the orientation based on current position and heading.
1448
- */
1449
1441
  GetOrient() {
1450
- // Update at 30 fps.
1451
1442
  let doUpdate = this.lastCalcOrientTime == null;
1452
1443
  if (!doUpdate && this.lastCalcOrientTime && (new Date().getTime() - this.lastCalcOrientTime) > 1000 / 30) {
1453
1444
  doUpdate = true;
@@ -1455,26 +1446,34 @@
1455
1446
  if (!doUpdate && this.lastCalcOrient) {
1456
1447
  return this.lastCalcOrient;
1457
1448
  }
1458
- // Default quaternion to return if we can't calculate.
1459
1449
  const defaultQuaternion = new Cesium.Quaternion();
1460
1450
  if (!this.positions || this.positions.length === 0) {
1461
1451
  return defaultQuaternion;
1462
1452
  }
1463
- // Ensure position is up-to-date.
1464
1453
  const currentPosition = this.GetValue();
1465
1454
  if (!currentPosition) {
1466
1455
  return defaultQuaternion;
1467
1456
  }
1468
- let now = this.viewer.scene.lastRenderTime;
1469
- if (!now) {
1470
- now = this.viewer.clock.currentTime;
1471
- }
1472
- const nowTime = Cesium.JulianDate.toDate(now).getTime();
1473
1457
  try {
1474
- // Get current position indices.
1458
+ const velocityMagnitude = Cesium.Cartesian3.magnitude(this.currentVelocity);
1459
+ const minimumSpeedForVelocityOrientation = Math.max(1.0, this.averageSpeed * 0.1);
1460
+ if (velocityMagnitude > minimumSpeedForVelocityOrientation) {
1461
+ const normalizedVelocity = Cesium.Cartesian3.normalize(this.currentVelocity, new Cesium.Cartesian3());
1462
+ const rotationMatrix = Cesium.Transforms.rotationMatrixFromPositionVelocity(currentPosition, normalizedVelocity);
1463
+ const quaternion = Cesium.Quaternion.fromRotationMatrix(rotationMatrix);
1464
+ const hpr = new Cesium.HeadingPitchRoll(0, Cesium.Math.toRadians(this.pitch), Cesium.Math.toRadians(this.roll));
1465
+ const pitchRollQuaternion = Cesium.Quaternion.fromHeadingPitchRoll(hpr);
1466
+ this.lastCalcOrient = Cesium.Quaternion.multiply(quaternion, pitchRollQuaternion, new Cesium.Quaternion());
1467
+ this.lastCalcOrientTime = Date.now();
1468
+ return this.lastCalcOrient;
1469
+ }
1470
+ let now = this.viewer.scene.lastRenderTime;
1471
+ if (!now) {
1472
+ now = this.viewer.clock.currentTime;
1473
+ }
1474
+ const nowTime = Cesium.JulianDate.toDate(now).getTime();
1475
1475
  const lastIndex = this.lastDesiredPosIndex;
1476
1476
  const nextIndex = this.lastDesiredNextIndex;
1477
- // Invalid indices.
1478
1477
  if (lastIndex < 0 || nextIndex < 0 ||
1479
1478
  lastIndex >= this.positions.length || nextIndex >= this.positions.length) {
1480
1479
  return this.lastCalcOrient || defaultQuaternion;
@@ -1484,74 +1483,53 @@
1484
1483
  if (!lastPos || !nextPos) {
1485
1484
  return this.lastCalcOrient || defaultQuaternion;
1486
1485
  }
1487
- // Single position case - use its heading if available.
1488
1486
  if (lastIndex === nextIndex) {
1489
1487
  if (lastPos.heading !== null) {
1490
1488
  this.lastCalcOrient = Cesium.Transforms.headingPitchRollQuaternion(currentPosition, new Cesium.HeadingPitchRoll(Cesium.Math.toRadians(lastPos.heading), Cesium.Math.toRadians(this.pitch), Cesium.Math.toRadians(this.roll)));
1491
1489
  this.lastCalcOrientTime = Date.now();
1492
1490
  return this.lastCalcOrient;
1493
1491
  }
1494
- // No heading data and single position, return previous or default.
1495
1492
  return this.lastCalcOrient || defaultQuaternion;
1496
1493
  }
1497
- // Two different positions - we can calculate orientation.
1498
- // Use explicit heading values if available.
1499
1494
  if (lastPos.heading !== null && nextPos.heading !== null) {
1500
- // Calculate interpolated heading.
1501
1495
  let deltaHeading = nextPos.heading - lastPos.heading;
1502
- // Handle wrap-around between 359° and 0°.
1503
1496
  if (deltaHeading > 180) {
1504
1497
  deltaHeading -= 360;
1505
1498
  }
1506
1499
  else if (deltaHeading < -180) {
1507
1500
  deltaHeading += 360;
1508
1501
  }
1509
- // Calculate interpolation factor.
1510
1502
  let factor = 0;
1511
1503
  if (lastPos.dateTime.getTime() !== nextPos.dateTime.getTime()) {
1512
- factor = (nowTime - lastPos.dateTime.getTime()) /
1513
- (nextPos.dateTime.getTime() - lastPos.dateTime.getTime());
1504
+ factor = (nowTime - lastPos.dateTime.getTime()) / (nextPos.dateTime.getTime() - lastPos.dateTime.getTime());
1514
1505
  factor = Math.max(0, Math.min(1, factor));
1515
1506
  }
1516
- // Apply easing for smoother rotation.
1517
1507
  factor = this.easeInOutQuad(factor);
1518
- // Calculate final heading.
1519
1508
  let interpolatedHeading = lastPos.heading + factor * deltaHeading;
1520
1509
  interpolatedHeading = (interpolatedHeading + 360) % 360;
1521
- // Create quaternion from heading, pitch, roll.
1522
1510
  this.lastCalcOrient = Cesium.Transforms.headingPitchRollQuaternion(currentPosition, new Cesium.HeadingPitchRoll(Cesium.Math.toRadians(interpolatedHeading), Cesium.Math.toRadians(this.pitch), Cesium.Math.toRadians(this.roll)));
1523
1511
  }
1524
- // Calculate heading from position changes if heading data not available.
1525
1512
  else {
1526
1513
  if (!lastPos.pos3d || !nextPos.pos3d) {
1527
1514
  return this.lastCalcOrient || defaultQuaternion;
1528
1515
  }
1529
- // Flatten positions to avoid altitude-related heading changes.
1530
1516
  const adjustedPointPrev = Cesium.Cartographic.fromCartesian(lastPos.pos3d);
1531
1517
  const adjustedPos3dPrev = Cesium.Cartesian3.fromRadians(adjustedPointPrev.longitude, adjustedPointPrev.latitude, 0);
1532
1518
  const adjustedPointNext = Cesium.Cartographic.fromCartesian(nextPos.pos3d);
1533
1519
  const adjustedPos3dNext = Cesium.Cartesian3.fromRadians(adjustedPointNext.longitude, adjustedPointNext.latitude, 0);
1534
- // Skip if positions are too close (less than 5cm).
1535
1520
  const distance = Cesium.Cartesian3.distance(adjustedPos3dPrev, adjustedPos3dNext);
1536
1521
  if (distance < 0.05) {
1537
1522
  return this.lastCalcOrient || defaultQuaternion;
1538
1523
  }
1539
- // Calculate direction vector.
1540
1524
  const direction = Cesium.Cartesian3.subtract(adjustedPos3dNext, adjustedPos3dPrev, new Cesium.Cartesian3());
1541
- // Skip if no movement.
1542
1525
  if (direction.x === 0 && direction.y === 0 && direction.z === 0) {
1543
1526
  return this.lastCalcOrient || defaultQuaternion;
1544
1527
  }
1545
- // Normalize the direction vector.
1546
1528
  Cesium.Cartesian3.normalize(direction, direction);
1547
- // Calculate rotation based on movement direction.
1548
1529
  const rotationMatrix = Cesium.Transforms.rotationMatrixFromPositionVelocity(currentPosition, direction);
1549
- // Convert to quaternion.
1550
1530
  const quaternion = Cesium.Quaternion.fromRotationMatrix(rotationMatrix);
1551
- // Add pitch and roll adjustments.
1552
1531
  const hpr = new Cesium.HeadingPitchRoll(0, Cesium.Math.toRadians(this.pitch), Cesium.Math.toRadians(this.roll));
1553
1532
  const pitchRollQuaternion = Cesium.Quaternion.fromHeadingPitchRoll(hpr);
1554
- // Combine quaternions.
1555
1533
  this.lastCalcOrient = Cesium.Quaternion.multiply(quaternion, pitchRollQuaternion, new Cesium.Quaternion());
1556
1534
  }
1557
1535
  }
@@ -1562,6 +1540,52 @@
1562
1540
  this.lastCalcOrientTime = Date.now();
1563
1541
  return this.lastCalcOrient;
1564
1542
  }
1543
+ GetCurrentVelocity() {
1544
+ return this.currentVelocity ? this.currentVelocity.clone() : new Cesium.Cartesian3(0, 0, 0);
1545
+ }
1546
+ SupplementSeries(newSeries) {
1547
+ if (!newSeries || newSeries.length === 0) {
1548
+ return;
1549
+ }
1550
+ for (const pos of newSeries) {
1551
+ if (!pos || !pos.pos3d || !pos.dateTime) {
1552
+ continue;
1553
+ }
1554
+ const existingIndex = this.positions.findIndex(p => p.dateTime.getTime() === pos.dateTime.getTime());
1555
+ if (existingIndex >= 0) {
1556
+ this.positions[existingIndex] = pos;
1557
+ }
1558
+ else {
1559
+ this.AddPosition(pos);
1560
+ }
1561
+ }
1562
+ }
1563
+ UpdatePositionForDateTime(pos3d, dateTime, heading) {
1564
+ if (!pos3d || !dateTime) {
1565
+ return;
1566
+ }
1567
+ const existingIndex = this.positions.findIndex(p => p.dateTime.getTime() === dateTime.getTime());
1568
+ const newPos = {
1569
+ pos3d: pos3d,
1570
+ dateTime: dateTime,
1571
+ heading: heading !== undefined ? heading : null
1572
+ };
1573
+ if (existingIndex >= 0) {
1574
+ this.positions[existingIndex] = newPos;
1575
+ this.processHeadings();
1576
+ this.sortPositions();
1577
+ this.invalidateCache();
1578
+ }
1579
+ else {
1580
+ this.AddPosition(newPos);
1581
+ }
1582
+ }
1583
+ HasPositionForDateTime(dateTime) {
1584
+ return this.positions.some(p => p.dateTime.getTime() === dateTime.getTime());
1585
+ }
1586
+ GetPositionCount() {
1587
+ return this.positions.length;
1588
+ }
1565
1589
  }
1566
1590
  CesiumAnimatedProperty.AnimatePositionSeries = AnimatePositionSeries;
1567
1591
  function GetSeriesPossesForHistoricEntity(viewer, dataHeightRef, heightRef, historic) {
@@ -5432,7 +5456,7 @@
5432
5456
  * @returns
5433
5457
  */
5434
5458
  async function Render(params) {
5435
- var _a, _b, _c, _d;
5459
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k;
5436
5460
  const entity = params.entity;
5437
5461
  if (!params.entityHistoric) {
5438
5462
  params.entityHistoric = [];
@@ -5633,39 +5657,69 @@
5633
5657
  // Unset width/height.
5634
5658
  cEntity.billboard.width = undefined;
5635
5659
  cEntity.billboard.height = undefined;
5660
+ const pos3d = exports.EntityUtils.GetPos({
5661
+ viewer: params.viewer,
5662
+ entity,
5663
+ recordHeightRef: heightRef,
5664
+ returnHeightRef: heightRef,
5665
+ allowRendered: false
5666
+ });
5636
5667
  const prevPos3d = GetCValue(params.viewer, cEntity.position);
5637
- let prevStartTime = null;
5638
5668
  if (cEntity.position && cEntity.position["CesiumAnimatedProperty.AnimatePositionSeries"]) {
5639
- prevStartTime = cEntity.position["CesiumAnimatedProperty.AnimatePositionSeries"].GetAnimateFromDateTime();
5640
- }
5641
- // If we have a series of time-based positions then we'll animate as time changes.
5642
- const series = exports.CesiumAnimatedProperty.GetSeriesPossesForHistoricEntity(params.viewer, heightRef, heightRef, params.entityHistoric);
5643
- if (series.length > 1) {
5644
- animatePosition = new exports.CesiumAnimatedProperty.AnimatePositionSeries({
5645
- posses: series,
5646
- viewer: params.viewer,
5647
- animateFromPos3d: prevPos3d,
5648
- animateFromPos3dTimeStart: prevStartTime
5649
- });
5650
- cEntity.position = new Cesium.CallbackProperty(() => animatePosition.GetValue(), false);
5651
- cEntity.position["CesiumAnimatedProperty.AnimatePositionSeries"] = animatePosition;
5669
+ animatePosition = cEntity.position["CesiumAnimatedProperty.AnimatePositionSeries"];
5670
+ const animateSeries = animatePosition;
5671
+ const series = exports.CesiumAnimatedProperty.GetSeriesPossesForHistoricEntity(params.viewer, heightRef, heightRef, params.entityHistoric);
5672
+ if (series.length) {
5673
+ animateSeries.SupplementSeries(series);
5674
+ }
5675
+ const dateTimeStr = (_d = (_c = entity.Bruce.Outline) === null || _c === void 0 ? void 0 : _c.find(x => !!x.DateTime)) === null || _d === void 0 ? void 0 : _d.DateTime;
5676
+ const dateTime = dateTimeStr ? new Date(dateTimeStr) : null;
5677
+ if (dateTime) {
5678
+ animateSeries.UpdatePositionForDateTime(pos3d, dateTime);
5679
+ }
5680
+ // We don't have a date-stamped incoming position.
5681
+ if (!dateTime && !series.length) {
5682
+ animatePosition = null;
5683
+ }
5652
5684
  }
5653
- else {
5654
- const pos3d = exports.EntityUtils.GetPos({
5655
- viewer: params.viewer,
5656
- entity,
5657
- recordHeightRef: heightRef,
5658
- returnHeightRef: heightRef,
5659
- allowRendered: false
5660
- });
5661
- if (!prevPos3d || !Cesium.Cartesian3.equals(prevPos3d, pos3d)) {
5662
- animatePosition = new exports.CesiumAnimatedProperty.AnimatePosition({
5663
- durationMs: 200,
5664
- targetPos3d: pos3d,
5665
- viewer: params.viewer,
5666
- startPos3d: prevPos3d
5685
+ if (!animatePosition) {
5686
+ // If we've loaded a set of series positions then we'll animate through them.
5687
+ const series = exports.CesiumAnimatedProperty.GetSeriesPossesForHistoricEntity(params.viewer, heightRef, heightRef, params.entityHistoric);
5688
+ if (series.length > 1) {
5689
+ animatePosition = new exports.CesiumAnimatedProperty.AnimatePositionSeries({
5690
+ posses: series,
5691
+ viewer: params.viewer
5667
5692
  });
5668
5693
  cEntity.position = new Cesium.CallbackProperty(() => animatePosition.GetValue(), false);
5694
+ cEntity.position["CesiumAnimatedProperty.AnimatePositionSeries"] = animatePosition;
5695
+ }
5696
+ else {
5697
+ const dateTimeStr = (_f = (_e = entity.Bruce.Outline) === null || _e === void 0 ? void 0 : _e.find(x => !!x.DateTime)) === null || _f === void 0 ? void 0 : _f.DateTime;
5698
+ const dateTime = dateTimeStr ? new Date(dateTimeStr) : null;
5699
+ const posChanged = !prevPos3d || !Cesium.Cartesian3.equals(prevPos3d, pos3d);
5700
+ if (posChanged) {
5701
+ let posses = [];
5702
+ const isLive = exports.ViewUtils.GetTimeDetails({ viewer: params.viewer }).isLive;
5703
+ if (prevPos3d && isLive) {
5704
+ posses.push({
5705
+ pos3d: prevPos3d,
5706
+ // Guess so that we can determine a direction of movement right away :)
5707
+ dateTime: new Date(dateTime.getTime() - 1000),
5708
+ heading: null
5709
+ });
5710
+ }
5711
+ posses.push({
5712
+ pos3d: pos3d,
5713
+ dateTime: dateTime,
5714
+ heading: null
5715
+ });
5716
+ animatePosition = new exports.CesiumAnimatedProperty.AnimatePositionSeries({
5717
+ posses: posses,
5718
+ viewer: params.viewer
5719
+ });
5720
+ cEntity.position = new Cesium.CallbackProperty(() => animatePosition.GetValue(), false);
5721
+ cEntity.position["CesiumAnimatedProperty.AnimatePositionSeries"] = animatePosition;
5722
+ }
5669
5723
  }
5670
5724
  }
5671
5725
  // We'll use "SetDefaultColor" to updating the internal reference and to allow for an animation.
@@ -5964,39 +6018,52 @@
5964
6018
  cEntity.billboard.heightReference = new Cesium.ConstantProperty(heightRef);
5965
6019
  cEntity.billboard.distanceDisplayCondition = new Cesium.ConstantProperty(exports.EntityRenderEngine.GetDisplayCondition(params.minDistance, params.maxDistance));
5966
6020
  cEntity.billboard.disableDepthTestDistance = new Cesium.ConstantProperty(disableDepthTest ? Number.POSITIVE_INFINITY : undefined);
6021
+ const pos3d = exports.EntityUtils.GetPos({
6022
+ viewer: params.viewer,
6023
+ entity,
6024
+ recordHeightRef: heightRef,
6025
+ returnHeightRef: heightRef,
6026
+ allowRendered: false
6027
+ });
5967
6028
  const prevPos3d = GetCValue(params.viewer, cEntity.position);
5968
- let prevStartTime = null;
5969
6029
  if (cEntity.position && cEntity.position["CesiumAnimatedProperty.AnimatePositionSeries"]) {
5970
- prevStartTime = cEntity.position["CesiumAnimatedProperty.AnimatePositionSeries"].GetAnimateFromDateTime();
5971
- }
5972
- // If we have a series of time-based positions then we'll animate as time changes.
5973
- const series = exports.CesiumAnimatedProperty.GetSeriesPossesForHistoricEntity(params.viewer, heightRef, heightRef, params.entityHistoric);
5974
- if (series.length > 1) {
5975
- animatePosition = new exports.CesiumAnimatedProperty.AnimatePositionSeries({
5976
- posses: series,
5977
- viewer: params.viewer,
5978
- animateFromPos3d: prevPos3d,
5979
- animateFromPos3dTimeStart: prevStartTime
5980
- });
5981
- cEntity.position = new Cesium.CallbackProperty(() => animatePosition.GetValue(), false);
5982
- cEntity.position["CesiumAnimatedProperty.AnimatePositionSeries"] = animatePosition;
5983
- }
5984
- else {
5985
- const pos3d = exports.EntityUtils.GetPos({
5986
- viewer: params.viewer,
5987
- entity,
5988
- recordHeightRef: heightRef,
5989
- returnHeightRef: heightRef,
5990
- allowRendered: false
5991
- });
5992
- if (!prevPos3d || !Cesium.Cartesian3.equals(prevPos3d, pos3d)) {
5993
- animatePosition = new exports.CesiumAnimatedProperty.AnimatePosition({
5994
- durationMs: 200,
5995
- targetPos3d: pos3d,
5996
- viewer: params.viewer,
5997
- startPos3d: prevPos3d
6030
+ animatePosition = cEntity.position["CesiumAnimatedProperty.AnimatePositionSeries"];
6031
+ const animateSeries = animatePosition;
6032
+ const series = exports.CesiumAnimatedProperty.GetSeriesPossesForHistoricEntity(params.viewer, heightRef, heightRef, params.entityHistoric);
6033
+ if (series.length) {
6034
+ animateSeries.SupplementSeries(series);
6035
+ }
6036
+ const dateTimeStr = (_h = (_g = entity.Bruce.Outline) === null || _g === void 0 ? void 0 : _g.find(x => !!x.DateTime)) === null || _h === void 0 ? void 0 : _h.DateTime;
6037
+ const dateTime = dateTimeStr ? new Date(dateTimeStr) : null;
6038
+ if (dateTime) {
6039
+ animateSeries.UpdatePositionForDateTime(pos3d, dateTime);
6040
+ }
6041
+ // We don't have a date-stamped incoming position.
6042
+ if (!dateTime && !series.length) {
6043
+ animatePosition = null;
6044
+ }
6045
+ }
6046
+ if (!animatePosition) {
6047
+ // If we have a series of time-based positions then we'll animate as time changes.
6048
+ const series = exports.CesiumAnimatedProperty.GetSeriesPossesForHistoricEntity(params.viewer, heightRef, heightRef, params.entityHistoric);
6049
+ if (series.length > 1) {
6050
+ animatePosition = new exports.CesiumAnimatedProperty.AnimatePositionSeries({
6051
+ posses: series,
6052
+ viewer: params.viewer
5998
6053
  });
5999
6054
  cEntity.position = new Cesium.CallbackProperty(() => animatePosition.GetValue(), false);
6055
+ cEntity.position["CesiumAnimatedProperty.AnimatePositionSeries"] = animatePosition;
6056
+ }
6057
+ else {
6058
+ if (!prevPos3d || !Cesium.Cartesian3.equals(prevPos3d, pos3d)) {
6059
+ animatePosition = new exports.CesiumAnimatedProperty.AnimatePosition({
6060
+ durationMs: 200,
6061
+ targetPos3d: pos3d,
6062
+ viewer: params.viewer,
6063
+ startPos3d: prevPos3d
6064
+ });
6065
+ cEntity.position = new Cesium.CallbackProperty(() => animatePosition.GetValue(), false);
6066
+ }
6000
6067
  }
6001
6068
  }
6002
6069
  // We'll use "SetDefaultColor" to updating the internal reference and to allow for an animation.
@@ -6015,7 +6082,7 @@
6015
6082
  // Generate a polyline 'track' for the historic data.
6016
6083
  // We do this for historic data that exists and is moving.
6017
6084
  if (shouldShowTrack && animatePosition && animatePosition instanceof exports.CesiumAnimatedProperty.AnimatePositionSeries && animatePosition.GetSeries) {
6018
- const lStyle = (_d = (_c = params.fullStyle) === null || _c === void 0 ? void 0 : _c.polylineStyle) !== null && _d !== void 0 ? _d : {};
6085
+ const lStyle = (_k = (_j = params.fullStyle) === null || _j === void 0 ? void 0 : _j.polylineStyle) !== null && _k !== void 0 ? _k : {};
6019
6086
  const bColor = lStyle.lineColor ? BModels.Calculator.GetColor(lStyle.lineColor, entity, params.tags) : null;
6020
6087
  const cColor = bColor ? ColorToCColor(bColor) : Cesium.Color.fromCssColorString("rgba(255, 193, 7, 0.8)");
6021
6088
  let width = lStyle.lineWidth ? EnsureNumber(BModels.Calculator.GetNumber(lStyle.lineWidth, entity, params.tags)) : 2;
@@ -7031,7 +7098,7 @@
7031
7098
  * @returns
7032
7099
  */
7033
7100
  function Render(params) {
7034
- var _a, _b, _c, _d;
7101
+ var _a, _b, _c, _d, _e, _f;
7035
7102
  const entity = params.entity;
7036
7103
  if (!params.entityHistoric) {
7037
7104
  params.entityHistoric = [];
@@ -7223,40 +7290,41 @@
7223
7290
  cEntity.model.colorBlendAmount = new Cesium.ConstantProperty(blendAmount);
7224
7291
  cEntity.model.colorBlendMode = new Cesium.ConstantProperty(blendMode);
7225
7292
  cEntity.model.distanceDisplayCondition = new Cesium.ConstantProperty(exports.EntityRenderEngine.GetDisplayCondition(params.minDistance, params.maxDistance));
7226
- let prevStartTime = null;
7227
7293
  if (cEntity.position && cEntity.position["CesiumAnimatedProperty.AnimatePositionSeries"]) {
7228
- prevStartTime = cEntity.position["CesiumAnimatedProperty.AnimatePositionSeries"].GetAnimateFromDateTime();
7229
- }
7230
- // If we've loaded a set of series positions then we'll animate through them.
7231
- const series = exports.CesiumAnimatedProperty.GetSeriesPossesForHistoricEntity(params.viewer, heightRef, heightRef, params.entityHistoric);
7232
- if (series.length > 1) {
7233
- animatePosition = new exports.CesiumAnimatedProperty.AnimatePositionSeries({
7234
- posses: series,
7235
- viewer: params.viewer,
7236
- pitch: pitch,
7237
- roll: roll,
7238
- animateFromPos3d: prevPos3d,
7239
- animateFromPos3dTimeStart: prevStartTime
7240
- });
7241
- cEntity.position = new Cesium.CallbackProperty(() => animatePosition.GetValue(), false);
7242
- cEntity.position["CesiumAnimatedProperty.AnimatePositionSeries"] = animatePosition;
7243
- }
7244
- else {
7294
+ animatePosition = cEntity.position["CesiumAnimatedProperty.AnimatePositionSeries"];
7295
+ const animateSeries = animatePosition;
7296
+ const series = exports.CesiumAnimatedProperty.GetSeriesPossesForHistoricEntity(params.viewer, heightRef, heightRef, params.entityHistoric);
7297
+ if (series.length) {
7298
+ animateSeries.SupplementSeries(series);
7299
+ }
7245
7300
  const dateTimeStr = (_b = (_a = entity.Bruce.Outline) === null || _a === void 0 ? void 0 : _a.find(x => !!x.DateTime)) === null || _b === void 0 ? void 0 : _b.DateTime;
7246
7301
  const dateTime = dateTimeStr ? new Date(dateTimeStr) : null;
7247
- const posChanged = !prevPos3d || !Cesium.Cartesian3.equals(prevPos3d, pos3d);
7248
- if (posChanged) {
7249
- if (cEntity.position["CesiumAnimatedProperty.AnimatePositionSeries"]) {
7250
- const prevAnimatePosition = cEntity.position["CesiumAnimatedProperty.AnimatePositionSeries"];
7251
- animatePosition = prevAnimatePosition;
7252
- animatePosition.AddPosition({
7253
- pos3d: pos3d,
7254
- dateTime: dateTime,
7255
- heading: !EnsureNumber(transform === null || transform === void 0 ? void 0 : transform.heading) ? null : heading
7256
- });
7257
- animatePosition.UpdatePitchRoll(pitch, roll);
7258
- }
7259
- else {
7302
+ if (dateTime) {
7303
+ animateSeries.UpdatePositionForDateTime(pos3d, dateTime, !EnsureNumber(transform === null || transform === void 0 ? void 0 : transform.heading) ? null : heading);
7304
+ }
7305
+ // We don't have a date-stamped incoming position.
7306
+ if (!dateTime && !series.length) {
7307
+ animatePosition = null;
7308
+ }
7309
+ }
7310
+ if (!animatePosition) {
7311
+ // If we've loaded a set of series positions then we'll animate through them.
7312
+ const series = exports.CesiumAnimatedProperty.GetSeriesPossesForHistoricEntity(params.viewer, heightRef, heightRef, params.entityHistoric);
7313
+ if (series.length > 1) {
7314
+ animatePosition = new exports.CesiumAnimatedProperty.AnimatePositionSeries({
7315
+ posses: series,
7316
+ viewer: params.viewer,
7317
+ pitch: pitch,
7318
+ roll: roll
7319
+ });
7320
+ cEntity.position = new Cesium.CallbackProperty(() => animatePosition.GetValue(), false);
7321
+ cEntity.position["CesiumAnimatedProperty.AnimatePositionSeries"] = animatePosition;
7322
+ }
7323
+ else {
7324
+ const dateTimeStr = (_d = (_c = entity.Bruce.Outline) === null || _c === void 0 ? void 0 : _c.find(x => !!x.DateTime)) === null || _d === void 0 ? void 0 : _d.DateTime;
7325
+ const dateTime = dateTimeStr ? new Date(dateTimeStr) : null;
7326
+ const posChanged = !prevPos3d || !Cesium.Cartesian3.equals(prevPos3d, pos3d);
7327
+ if (posChanged) {
7260
7328
  let posses = [];
7261
7329
  const isLive = exports.ViewUtils.GetTimeDetails({ viewer: params.viewer }).isLive;
7262
7330
  if (prevPos3d && isLive) {
@@ -7276,9 +7344,7 @@
7276
7344
  posses: posses,
7277
7345
  viewer: params.viewer,
7278
7346
  pitch: pitch,
7279
- roll: roll,
7280
- animateFromPos3d: prevPos3d && !isLive ? prevPos3d : null,
7281
- animateFromPos3dTimeStart: null
7347
+ roll: roll
7282
7348
  });
7283
7349
  cEntity.position = new Cesium.CallbackProperty(() => animatePosition.GetValue(), false);
7284
7350
  cEntity.position["CesiumAnimatedProperty.AnimatePositionSeries"] = animatePosition;
@@ -7431,7 +7497,7 @@
7431
7497
  // Generate a polyline 'track' for the historic data.
7432
7498
  // We do this for historic data that exists and is moving.
7433
7499
  if (shouldShowTrack && animatePosition && animatePosition instanceof exports.CesiumAnimatedProperty.AnimatePositionSeries && animatePosition.GetSeries) {
7434
- const lStyle = (_d = (_c = params.fullStyle) === null || _c === void 0 ? void 0 : _c.polylineStyle) !== null && _d !== void 0 ? _d : {};
7500
+ const lStyle = (_f = (_e = params.fullStyle) === null || _e === void 0 ? void 0 : _e.polylineStyle) !== null && _f !== void 0 ? _f : {};
7435
7501
  const bColor = lStyle.lineColor ? BModels.Calculator.GetColor(lStyle.lineColor, entity, params.tags) : null;
7436
7502
  const cColor = bColor ? ColorToCColor(bColor) : Cesium.Color.fromCssColorString("rgba(255, 193, 7, 0.8)");
7437
7503
  let width = lStyle.lineWidth ? EnsureNumber(BModels.Calculator.GetNumber(lStyle.lineWidth, entity, params.tags)) : 2;
@@ -33139,7 +33205,7 @@
33139
33205
  }
33140
33206
  }
33141
33207
 
33142
- const VERSION = "5.9.6";
33208
+ const VERSION = "5.9.8";
33143
33209
 
33144
33210
  exports.VERSION = VERSION;
33145
33211
  exports.isOutlineChanged = isOutlineChanged;