Remove RouteTrack class

This commit is contained in:
dominik-korsa 2025-07-19 15:17:45 +02:00
parent 56c1360e30
commit e3b34cd149
No known key found for this signature in database
GPG Key ID: 5A24D76EE0A30974
10 changed files with 92 additions and 130 deletions

View File

@ -4,6 +4,7 @@ import Constants from "../../../helpers/constants";
import { ElectrificationStatus } from "../../../model/electrification-status";
import MiscHelper from "../../../helpers/miscHelper";
import { setHoveredTrack, unsetHoveredTrack } from "../../../services/trackHoverInfoService";
import {TrackSource} from "../../../model/tracks/track";
export default function TrackRenderer(props) {
const { object } = props;
@ -109,14 +110,14 @@ function getTrackColor(object, trackColorMode) {
}
case "type":
switch (object.type) {
case "StandardTrack":
switch (object.source) {
case TrackSource.STANDARD:
return modeDef.options['standard-track'][0];
case "PointTrack":
case TrackSource.SWITCH:
return modeDef.options['point-track'][0];
case "RouteTrack":
case TrackSource.ROUTE:
return modeDef.options['route-track'][0];
case "BezierTrack":
case TrackSource.BEZIER:
return modeDef.options['bezier-track'][0];
default:
return modeDef.options[modeDef.optionDefault][0];

View File

@ -1,4 +1,5 @@
import { ElectrificationStatus } from "../../../model/electrification-status";
import {TrackSource} from "../../../model/tracks/track";
const TrackHoverInfoConsts = {
electrification: {
@ -7,11 +8,11 @@ const TrackHoverInfoConsts = {
[ElectrificationStatus.NOT_CHECKED]: 'Unknown',
[ElectrificationStatus.CONFLICT]: 'Error / Conflict',
},
type: {
'StandardTrack': 'Standard track',
'PointTrack': 'Switch track',
'BezierTrack': 'Bezier track',
'RouteTrack': 'Route track',
source: {
[TrackSource.STANDARD]: 'Standard track',
[TrackSource.SWITCH]: 'Switch track',
[TrackSource.BEZIER]: 'Bezier track',
[TrackSource.ROUTE]: 'Route track',
}
};

View File

@ -19,7 +19,7 @@ export default function TrackHoverInfoPopup(props) {
<InfoPopupItem value={track['maxspeed']} label="Max. speed" options={{suffix: ' km/h'}} />
<InfoPopupItem value={slopeArr} label="Slope" options={slopeOptions} />
<InfoPopupItem value={track['electrificationStatus']} label="Electrification" options={{translationConstKey: 'electrification'}} />
<InfoPopupItem value={track['type']} label="Type" options={{translationConstKey: 'type'}} />
<InfoPopupItem value={track['source']} label="Type" options={{translationConstKey: 'source'}} />
<InfoPopupSwitchItems track={track} />
</tbody>
</table>

View File

@ -1,6 +1,7 @@
import TrackConnection, {TrackConnectionEnd} from "./track-connection";
import SceneryParserLog from "./scenery-parser-log";
import Constants from "../helpers/constants";
import {TrackSource} from "./tracks/track";
const connectionThresholdDistanceSq = 0.05;
@ -32,8 +33,7 @@ function _applyTrackConnection(scenery, track, connection) {
connection.otherTrack = otherTrack;
// route tracks dont have reverse connections saved in file, so we add them here
const isRouteTrack = otherTrack.type === 'RouteTrack';
if (isRouteTrack) {
if (otherTrack.source === TrackSource.ROUTE) {
const reverseConnection = new TrackConnection(track, TrackConnectionEnd.START);
otherTrack.connections.push(reverseConnection);
}
@ -42,6 +42,8 @@ function _applyTrackConnection(scenery, track, connection) {
}
function _testTrackConnection(track, connection) {
if (!connection.otherTrack) return;
const reverseConnections = connection.otherTrack.connections.filter(
(otherConnection) => otherConnection.otherTrackId === track.id,
);

View File

@ -1,8 +1,9 @@
import SceneryObject from "./scenery-object";
import Vector3 from "./vector3";
import SceneryParserLog from "./scenery-parser-log";
import RouteTrack from "./tracks/route-track";
import TrackConnection, {TrackConnectionEnd} from "./track-connection";
import CurveHelper from "../helpers/curveHelper";
import StandardTrack from "./tracks/standard-track";
import AngleHelper from "../helpers/angleHelper";
export default class Route extends SceneryObject {
@ -17,7 +18,6 @@ export default class Route extends SceneryObject {
offsets;
segments = [];
end_center;
end_points;
end_angle_rad;
constructor(prefab_name, pos, rot, track_count, route_name, track_offset, electrified) {
@ -34,13 +34,12 @@ export default class Route extends SceneryObject {
this.offsets = this._getOffsets();
this.end_angle_rad = this.rot.y * Math.PI / 180;
this.end_center = this.pos.clone();
this.end_points = this._getConnectionPoints();
this.points = [...this.end_points];
this.points = [this.pos.clone()];
}
static fromText(text) {
const values = text.split(";");
const route = new Route(
return new Route(
values[2], // prefab_name
Vector3.fromValuesArray(values, 3), // pos
Vector3.fromValuesArray(values, 6), // rot
@ -49,8 +48,6 @@ export default class Route extends SceneryObject {
parseFloat(values[11]) || 0, // center_offset
values[13] === "True" || values[12] === "1" // electrified
);
return route;
}
addSegment(length, radius, trackIds) {
@ -58,67 +55,43 @@ export default class Route extends SceneryObject {
SceneryParserLog.warn('routeInvalidSegment', `Route segment has invalid track count: expected ${this.track_count}, got ${trackIds.length}`);
return;
}
const startAngleRad = this.end_angle_rad;
const startRot = new Vector3(0, AngleHelper.radToDeg(startAngleRad), 0);
const rotDeg = new Vector3(0, AngleHelper.radToDeg(this.end_angle_rad), 0);
const perpendicularUnitVec = Vector3.fromAngleY(this.end_angle_rad + Math.PI / 2);
const startPoints = this.end_points;
this.end_points = [];
const tracks = this.offsets.map((offset, index) => {
const startPoint = this.end_center.add(perpendicularUnitVec.multiply(offset));
const radii = [];
const lengths = [];
let trackRadius = radius;
let trackLength = length;
if (radius !== 0) {
trackRadius += offset;
trackLength *= (trackRadius / radius);
}
if (radius === 0) {
this.end_center = this.end_center.add(Vector3.fromAngleY(startAngleRad, length));
this.offsets.forEach(offset => {
radii.push(0);
lengths.push(length);
const end_point = this.end_center
.add(Vector3.fromAngleY(this.end_angle_rad + Math.PI / 2, offset));
this.end_points.push(end_point);
});
} else {
this.end_angle_rad -= length / radius;
const startToCenter = Vector3.fromAngleY(startAngleRad + Math.sign(radius) * Math.PI / 2, Math.abs(radius));
const circleCenter = this.end_center.add(startToCenter.negate());
const centerToEndUnit = Vector3.fromAngleY(this.end_angle_rad + Math.sign(radius) * Math.PI / 2, 1).multiply(Math.sign(radius));
this.end_center = circleCenter.add(centerToEndUnit.multiply(radius));
this.offsets.forEach(offset => {
const trackRadius = radius + offset;
const trackLength = length * trackRadius / radius;
radii.push(trackRadius);
lengths.push(trackLength);
const end_point = circleCenter.add(centerToEndUnit.multiply(trackRadius));
this.end_points.push(end_point);
});
}
this.points.push(...this.end_points);
const tracks = trackIds.map((trackId, index) => {
return new RouteTrack(
trackId,
startPoints[index],
this.end_points[index],
startRot,
lengths[index],
radii[index],
return StandardTrack.route(
trackIds[index],
startPoint,
rotDeg,
trackLength,
trackRadius,
[], // connections
this.electrified,
this, // route
);
});
if (this.segments.length >= 2) {
const prevSegment = this.segments[this.segments.length - 2];
const newSegment = this.segments[this.segments.length - 1];
newSegment.tracks.forEach((track, index) => {
const { endPos: centerEndPos, endAngle } = CurveHelper.calculateCurveEnd(this.end_center, this.end_angle_rad, radius, length);
this.end_center = centerEndPos;
this.end_angle_rad = endAngle;
if (this.segments.length > 0) {
const prevSegment = this.segments[this.segments.length - 1];
tracks.forEach((track, index) => {
const prevTrack = prevSegment.tracks[index];
track.connections.push(new TrackConnection(prevTrack, TrackConnectionEnd.START));
prevTrack.connections.push(new TrackConnection(track, TrackConnectionEnd.END));
});
}
this.segments.push({ length, radius, trackIds, tracks });
}
@ -132,13 +105,6 @@ export default class Route extends SceneryObject {
return result;
}
_getConnectionPoints() {
return this.offsets.map((offset) => {
const offsetVec = Vector3.fromAngleY(this.end_angle_rad + Math.PI / 2, offset);
return this.pos.add(offsetVec);
});
}
applyObject(scenery) {
if(this.applied) return; // already applied
this.applied = true;
@ -149,4 +115,10 @@ export default class Route extends SceneryObject {
});
});
}
getRenderBounds() {
// These points are used for rendering the route name and arrow
// Route segment endpoints are not included here
return [this.pos, this.end_center];
}
}

View File

@ -1,4 +1,4 @@
import Track from "./track";
import Track, {TrackSource} from "./track";
import Vector3 from "../vector3";
import TrackConnection, {TrackConnectionEnd} from "../track-connection";
@ -14,7 +14,7 @@ export default class BezierTrack extends Track
};
constructor(id, start, control1, end, control2, rot, len, r, connections, id_station, start_slope, end_slope, id_isolation, prefab_name, maxspeed, derailspeed) {
super(id, start, rot, len, r, connections, id_station, start_slope, end_slope, id_isolation, prefab_name, maxspeed, derailspeed);
super(id, start, rot, len, r, connections, id_station, start_slope, end_slope, id_isolation, prefab_name, maxspeed, derailspeed, TrackSource.BEZIER);
Object.assign(this.points, {
start,

View File

@ -1,5 +1,5 @@
import AngleHelper from '../../helpers/angleHelper';
import Track from './track';
import Track, {TrackSource} from './track';
import Vector3 from '../vector3';
export default class PointTrack extends Track
@ -12,7 +12,7 @@ export default class PointTrack extends Track
constructor(id, start, end, r, connections, id_station, start_slope, end_slope, id_isolation, prefab_name, maxspeed, derailspeed) {
const [rot, len] = PointTrack._getRotLen(start, end, r);
super(id, start, rot, len, r, connections, id_station, start_slope, end_slope, id_isolation, prefab_name, maxspeed, derailspeed);
super(id, start, rot, len, r, connections, id_station, start_slope, end_slope, id_isolation, prefab_name, maxspeed, derailspeed, TrackSource.SWITCH);
Object.assign(this.points, {
start, end

View File

@ -1,42 +0,0 @@
import AngleHelper from "../../helpers/angleHelper";
import Track from "./track";
import {ElectrificationStatus} from "../electrification-status";
export default class RouteTrack extends Track {
type = "RouteTrack";
points;
route;
constructor(id, start, end, rot, len, r, connections, electrified, route) {
super(
id, start, rot, len, r, connections,
null, // id_station,
0, // start_slope,
0, // end_slope,
null, // id_isolation
null, // prefab_name
null, // maxspeed,
null, // derailspeed,
);
this.electrificationStatus = electrified ? ElectrificationStatus.ELECTRIFIED : ElectrificationStatus.NON_ELECTRIFIED;
this.points = {
start,
end,
};
this.route = route;
}
getStartAngleXZ() {
return AngleHelper.degToRad(this.rot.y);
}
getEndAngleXZ() {
const startAngle = AngleHelper.degToRad(this.rot.y);
if(this.r === 0) {
return startAngle
}
return startAngle - this.len / this.r;
}
}

View File

@ -1,10 +1,10 @@
import AngleHelper from "../../helpers/angleHelper";
import Track from "./track";
import Track, {TrackSource} from "./track";
import Vector3 from "../vector3";
import TrackConnection, {TrackConnectionEnd} from "../track-connection";
import {ElectrificationStatus} from "../electrification-status";
export default class StandardTrack extends Track
{
export default class StandardTrack extends Track {
type = "StandardTrack";
points = {
start: Vector3.zero(),
@ -13,8 +13,8 @@ export default class StandardTrack extends Track
middle: Vector3.zero(),
};
constructor(id, start, rot, len, r, connections, id_station, start_slope, end_slope, id_isolation, prefab_name, maxspeed, derailspeed) {
super(id, start, rot, len, r, connections, id_station, start_slope, end_slope, id_isolation, prefab_name, maxspeed, derailspeed);
constructor(id, start, rot, len, r, connections, id_station, start_slope, end_slope, id_isolation, prefab_name, maxspeed, derailspeed, source = TrackSource.STANDARD) {
super(id, start, rot, len, r, connections, id_station, start_slope, end_slope, id_isolation, prefab_name, maxspeed, derailspeed, source);
this._calcPoints();
}
@ -89,4 +89,22 @@ export default class StandardTrack extends Track
applyObject(scenery) {
super.applyObject(scenery);
}
static route(id, start, rot, len, r, connections, electrified, route) {
const track = new StandardTrack(
id, start, rot, len, r,
connections,
null, // id_station,
0, // start_slope,
0, // end_slope,
null, // id_isolation
null, // prefab_name
null, // maxspeed,
null, // derailspeed,
TrackSource.ROUTE,
);
track.electrificationStatus = electrified ? ElectrificationStatus.ELECTRIFIED : ElectrificationStatus.NON_ELECTRIFIED;
track.route = route;
return track;
}
}

View File

@ -2,6 +2,13 @@ import SceneryObject from "../scenery-object";
import { ElectrificationStatus } from "../electrification-status";
import {TrackConnectionEnd} from "../track-connection";
export const TrackSource = {
STANDARD: Symbol("TrackSource.STANDARD"),
BEZIER: Symbol("TrackSource.BEZIER"),
SWITCH: Symbol("TrackSource.SWITCH"),
ROUTE: Symbol("TrackSource.ROUTE"),
};
export default class Track extends SceneryObject {
len;
r;
@ -16,10 +23,12 @@ export default class Track extends SceneryObject {
end_slope;
prefab_name;
switch = null;
route = null;
electrificationStatus = ElectrificationStatus.NOT_CHECKED;
hasNEVP = false;
source;
constructor(id, pos, rot, len, r, connections, id_station, start_slope, end_slope, id_isolation, prefab_name, maxspeed, derailspeed) {
constructor(id, pos, rot, len, r, connections, id_station, start_slope, end_slope, id_isolation, prefab_name, maxspeed, derailspeed, source) {
super(id, pos, rot);
Object.assign(this, {
len, r,
@ -29,6 +38,7 @@ export default class Track extends SceneryObject {
id_isolation,
prefab_name,
maxspeed, derailspeed,
source,
});
}