td2-visualizer/src/helpers/curveHelper.js
izawartka 20a46f7bba Implement switch slope calculation
- Implemented track slope calculation in switch tracks
2026-08-13 21:48:43 +02:00

79 lines
2.8 KiB
JavaScript

import Vector3 from "../model/vector3";
import AngleHelper from "./angleHelper";
import Quaternion from "../model/quaternion";
function calculateCurveEnd(startPos, startAngle, radius, curveLength) {
if (radius === 0) {
return {
endPos: startPos.add(Vector3.fromAngleY(startAngle, curveLength)),
endAngle: startAngle,
circleCenter: null,
};
}
const centerToStart = Vector3.fromAngleY(startAngle + Math.sign(radius) * Math.PI / 2, Math.abs(radius));
const circleCenter = startPos.add(centerToStart.negate());
const endAngle = startAngle -curveLength / radius;
const centerToEnd = Vector3.fromAngleY(endAngle + Math.sign(radius) * Math.PI / 2, Math.abs(radius));
const endPos = circleCenter.add(centerToEnd);
return { endPos, endAngle, circleCenter };
}
/**
* Does the same as calculateCurveEnd with `startPos = Vector3.zero()` and `startAngle = 0`.
*/
function calculateCurveEndStandard(radius, curveLength) {
if (radius === 0) {
return {
endPos: new Vector3(0, 0, curveLength),
endAngle: 0,
circleCenter: null,
};
}
const circleCenter = new Vector3(-radius, 0, 0);
const endAngle = -curveLength / radius;
const centerToEnd = Vector3.fromAngleY(endAngle + Math.sign(radius) * Math.PI / 2, Math.abs(radius));
const endPos = circleCenter.add(centerToEnd);
return { endPos, endAngle, circleCenter };
}
function transformStart(globalStart, globalRotationDeg, localStart, localRotationQuat) {
const globalRotationRad = AngleHelper.vectorDegToRad(globalRotationDeg);
const startPos = globalStart.add(localStart.rotate(globalRotationRad));
const rotationQuat = Quaternion.fromEulerAnglesRad(globalRotationRad).multiply(localRotationQuat);
const rotationRad = rotationQuat.toEulerAnglesRad();
const rotationDeg = AngleHelper.vectorRadToDeg(rotationRad);
return {
startPos,
rotationQuat,
rotationDeg,
};
}
function calculateSlopesFromQuaternion(rotationQuat, radius, length) {
const startTangent = new Vector3(0, 0, 1);
const endTangent = radius === 0
? startTangent
: Vector3.fromAngleY(-length / radius);
const worldStart = rotationQuat.rotateVector(startTangent);
const worldEnd = rotationQuat.rotateVector(endTangent);
const startHorizontal = Math.hypot(worldStart.x, worldStart.z);
const endHorizontal = Math.hypot(worldEnd.x, worldEnd.z);
return {
startSlope: startHorizontal === 0 ? 0 : (worldStart.y / startHorizontal) * 1000,
endSlope: endHorizontal === 0 ? 0 : (worldEnd.y / endHorizontal) * 1000,
};
}
const CurveHelper = {
calculateCurveEnd,
calculateCurveEndStandard,
transformStart,
calculateSlopesFromQuaternion
};
export default CurveHelper;