fix(preview): align traffic-aware vehicles to roads
This commit is contained in:
@@ -15,6 +15,11 @@
|
||||
const toggleFps = document.getElementById("toggleFps");
|
||||
const toggleDiagnostics = document.getElementById("toggleDiagnostics");
|
||||
const assetToggles = document.getElementById("assetToggles");
|
||||
// The exported road surface sits at the 0.35m scene anchor plus 0.03m.
|
||||
// Vehicle models have their wheels at local Y=0, so keep them just clear
|
||||
// of the asphalt instead of using the old visibly floating 1.15m height.
|
||||
const VEHICLE_HEIGHT_METERS = 0.40;
|
||||
const ROUTE_LINE_HEIGHT_METERS = 0.42;
|
||||
const semanticToggles = document.getElementById("semanticToggles");
|
||||
const vehicleSelect = document.getElementById("vehicleSelect");
|
||||
const speedControl = document.getElementById("speedControl");
|
||||
@@ -591,10 +596,11 @@
|
||||
|
||||
function addCruiseVehicle(viewer, segment, index, start, speed, signalData, vehicleModelName) {
|
||||
const route = prepareRoute(segment, signalData);
|
||||
const positions = createTrafficAwarePositions(viewer, route, start, speed);
|
||||
const trafficMotion = createTrafficAwarePositions(viewer, route, start, speed);
|
||||
const positions = trafficMotion.positions;
|
||||
const flat = [];
|
||||
for (const coord of segment.coordinates) {
|
||||
flat.push(coord[0], coord[1], 1.05);
|
||||
flat.push(coord[0], coord[1], ROUTE_LINE_HEIGHT_METERS);
|
||||
}
|
||||
const routeColor = [
|
||||
Cesium.Color.CYAN,
|
||||
@@ -616,7 +622,7 @@
|
||||
const vehicle = viewer.entities.add({
|
||||
name: "Cruise vehicle " + (index + 1),
|
||||
position: positions,
|
||||
orientation: routeOrientationFromPositions(positions),
|
||||
orientation: routeOrientationFromState(route, trafficMotion.state, speed, 0.0),
|
||||
model: {
|
||||
uri: vehicleModelName,
|
||||
// Keep the library's world scale visible. A minimum screen size made
|
||||
@@ -686,7 +692,6 @@
|
||||
|
||||
function createTrafficAwarePositions(viewer, route, start, speed) {
|
||||
const state = { distance: 0, lastTime: start.clone() };
|
||||
const scratchTime = new Cesium.JulianDate();
|
||||
viewer.clock.onTick.addEventListener((clock) => {
|
||||
const elapsed = Cesium.JulianDate.secondsDifference(clock.currentTime, state.lastTime);
|
||||
Cesium.JulianDate.clone(clock.currentTime, state.lastTime);
|
||||
@@ -702,7 +707,10 @@
|
||||
}
|
||||
state.distance = (state.distance + advance) % route.length;
|
||||
});
|
||||
return new Cesium.CallbackProperty((time, result) => routePositionAtDistance(route, state.distance, result), false);
|
||||
return {
|
||||
state,
|
||||
positions: new Cesium.CallbackProperty((time, result) => routePositionAtDistance(route, state.distance, result), false),
|
||||
};
|
||||
}
|
||||
|
||||
function nextRouteStop(route, distance) {
|
||||
@@ -727,7 +735,7 @@
|
||||
const b = route.coordinates[index];
|
||||
const lon = a[0] + (b[0] - a[0]) * t;
|
||||
const lat = a[1] + (b[1] - a[1]) * t;
|
||||
return Cesium.Cartesian3.fromDegrees(lon, lat, 1.15, Cesium.Ellipsoid.WGS84, result);
|
||||
return Cesium.Cartesian3.fromDegrees(lon, lat, VEHICLE_HEIGHT_METERS, Cesium.Ellipsoid.WGS84, result);
|
||||
}
|
||||
|
||||
function routeOrientation(route, start, speed, yawDegrees) {
|
||||
@@ -776,8 +784,41 @@
|
||||
}, false);
|
||||
}
|
||||
|
||||
function routeOrientationFromPositions(positions) {
|
||||
return new Cesium.VelocityOrientationProperty(positions);
|
||||
function routeOrientationFromState(route, state, speed, yawDegrees) {
|
||||
const correction = Cesium.Quaternion.fromAxisAngle(
|
||||
Cesium.Cartesian3.UNIT_Z,
|
||||
Cesium.Math.toRadians(yawDegrees)
|
||||
);
|
||||
const current = new Cesium.Cartesian3();
|
||||
const ahead = new Cesium.Cartesian3();
|
||||
const direction = new Cesium.Cartesian3();
|
||||
const up = new Cesium.Cartesian3();
|
||||
const east = new Cesium.Cartesian3();
|
||||
const north = new Cesium.Cartesian3();
|
||||
const hpr = new Cesium.HeadingPitchRoll(0.0, 0.0, 0.0);
|
||||
const base = new Cesium.Quaternion();
|
||||
return new Cesium.CallbackProperty((time, result) => {
|
||||
routePositionAtDistance(route, state.distance, current);
|
||||
// Sample a small distance ahead, rather than using velocity. This keeps
|
||||
// the car aligned while stopped and preserves the model's route heading.
|
||||
const lookAhead = Math.max(0.8, speed * 0.8);
|
||||
routePositionAtDistance(route, (state.distance + lookAhead) % route.length, ahead);
|
||||
Cesium.Cartesian3.subtract(ahead, current, direction);
|
||||
if (Cesium.Cartesian3.magnitudeSquared(direction) < 0.0001) return result;
|
||||
Cesium.Cartesian3.normalize(direction, direction);
|
||||
Cesium.Cartesian3.normalize(current, up);
|
||||
Cesium.Cartesian3.cross(Cesium.Cartesian3.UNIT_Z, up, east);
|
||||
if (Cesium.Cartesian3.magnitudeSquared(east) < 0.0001) {
|
||||
Cesium.Cartesian3.clone(Cesium.Cartesian3.UNIT_X, east);
|
||||
} else {
|
||||
Cesium.Cartesian3.normalize(east, east);
|
||||
}
|
||||
Cesium.Cartesian3.cross(up, east, north);
|
||||
Cesium.Cartesian3.normalize(north, north);
|
||||
hpr.heading = Math.atan2(Cesium.Cartesian3.dot(direction, east), Cesium.Cartesian3.dot(direction, north));
|
||||
Cesium.Transforms.headingPitchRollQuaternion(current, hpr, undefined, undefined, base);
|
||||
return Cesium.Quaternion.multiply(base, correction, result || new Cesium.Quaternion());
|
||||
}, false);
|
||||
}
|
||||
|
||||
function createChaseFollow(viewer, positionsProvider) {
|
||||
|
||||
Reference in New Issue
Block a user