diff --git a/public/assets/route.svg b/public/assets/route.svg
new file mode 100644
index 0000000..7afae49
--- /dev/null
+++ b/public/assets/route.svg
@@ -0,0 +1,7 @@
+
+
diff --git a/src/components/map/Map.css b/src/components/map/Map.css
index 64851bf..08a77bf 100644
--- a/src/components/map/Map.css
+++ b/src/components/map/Map.css
@@ -15,7 +15,6 @@
}
.map svg text.switch-name {
- fill: #eee;
fill: #bbf;
}
@@ -38,4 +37,13 @@
.map svg g.signal g {
stroke: #eee;
+}
+
+.map svg g.route g {
+ fill: #eee;
+}
+
+.map svg g.route text {
+ fill: #eee;
+ font-size: 72mm;
}
\ No newline at end of file
diff --git a/src/components/map/ObjectsRenderQueue.js b/src/components/map/ObjectsRenderQueue.js
index 7307b8f..e0a2b5d 100644
--- a/src/components/map/ObjectsRenderQueue.js
+++ b/src/components/map/ObjectsRenderQueue.js
@@ -3,6 +3,7 @@ import SwitchNameRenderer from './object-renderers/SwitchNameRenderer';
import IsolationIdRenderer from './object-renderers/IsolationIdRenderer';
import TrackObjectRenderer from './object-renderers/TrackObjectRenderer';
import SignalRenderer from './object-renderers/SignalRenderer';
+import RouteRenderer from './object-renderers/RouteRenderer';
const ObjectRendererQueue = [
{
@@ -36,6 +37,12 @@ const ObjectRendererQueue = [
'type': 'Signal',
'renderer': SignalRenderer,
'cond': (settings) => settings.layers['signals']
+ },
+ {
+ 'name': 'routes',
+ 'category': 'routes',
+ 'renderer': RouteRenderer,
+ 'cond': (settings) => settings.layers['routes']
}
]
diff --git a/src/components/map/SceneryRoot.js b/src/components/map/SceneryRoot.js
index 37fb4b7..f7753e2 100644
--- a/src/components/map/SceneryRoot.js
+++ b/src/components/map/SceneryRoot.js
@@ -18,12 +18,16 @@ export default function SceneryRoot(props) {
const objects = scenery.objects[category] ?? null;
if(!objects) return [null];
- return Object.values(objects).map((object) => {
- if((type !== undefined && type !== object.type) || (types !== undefined && !types.includes(object.type))) return null;
+ return (
+
+ {Object.values(objects).map((object) => {
+ if((type !== undefined && type !== object.type) || (types !== undefined && !types.includes(object.type))) return null;
- return ;
- });
- }).flat();
+ return ;
+ })}
+
+ );
+ });
}, [scenery, settings]);
return (
diff --git a/src/components/map/object-renderers/RouteRenderer.js b/src/components/map/object-renderers/RouteRenderer.js
new file mode 100644
index 0000000..846f9b7
--- /dev/null
+++ b/src/components/map/object-renderers/RouteRenderer.js
@@ -0,0 +1,44 @@
+import { useMemo } from "react";
+import { ReactSVG } from "react-svg";
+
+export default function RouteRenderer(props) {
+ const { object } = props;
+
+ const x = object.x;
+ const z = -object.z;
+
+ const upsideDown = useMemo(() => {
+ let rot = object.rot;
+ if (rot < 0) {
+ rot += 360 * Math.ceil(Math.abs(rot) / 360);
+ } else if (rot >= 360) {
+ rot -= 360 * Math.floor(rot / 360);
+ }
+
+ return rot > 180;
+ }, [object.rot]);
+
+ const upsideDownRot = upsideDown ? 90 : -90;
+ const offY = object.track_count === 2 ? -22 : 20;
+ const anchor = upsideDown ? "start" : "end";
+
+ return (
+
+
+ {
+ svg.setAttribute('width', '20mm');
+ svg.setAttribute('height', '20mm');
+ }}
+ />
+
+
+
+ {object.route_name}
+
+
+
+ );
+}
diff --git a/src/helpers/constants.js b/src/helpers/constants.js
index 4bad6dc..363a2eb 100644
--- a/src/helpers/constants.js
+++ b/src/helpers/constants.js
@@ -28,6 +28,11 @@ const Constants = {
id: 'signals',
name: 'Signals',
default: true,
+ },
+ {
+ id: 'routes',
+ name: 'Routes',
+ default: true,
}
]
};
diff --git a/src/model/route.js b/src/model/route.js
new file mode 100644
index 0000000..73d2abe
--- /dev/null
+++ b/src/model/route.js
@@ -0,0 +1,43 @@
+import SceneryObject from "./scenery-object";
+
+export default class Route extends SceneryObject {
+ track_count;
+ route_name;
+ electrified;
+ track_offset;
+ category = "routes";
+ type = "Route";
+
+ constructor(prefab_name, x, y, z, rot, track_count, route_name, track_offset, electrified) {
+ super(route_name, x, y, z);
+
+ Object.assign(this, {
+ prefab_name,
+ rot,
+ track_count,
+ route_name,
+ track_offset,
+ electrified,
+ });
+ }
+
+ // Route;;ConnectionForest;14418.61;-6.663832;8637.426;0;33.34996;0;2;Ol;2;;True
+
+ static fromText(text) {
+ const values = text.split(";");
+ const route = new Route(
+ values[2], // prefab_name
+ parseFloat(values[3]), // x
+ parseFloat(values[4]), // y
+ parseFloat(values[5]), // z
+ parseFloat(values[7]), // rot
+ parseInt(values[9]), // track_count
+ values[10], // route_name
+ parseFloat(values[11]), // track_offset
+ values[13] === "True" || values[12] === "1" // electrified
+ );
+
+ return route;
+ }
+
+}
\ No newline at end of file
diff --git a/src/model/scenery.js b/src/model/scenery.js
index a1b93cf..4cbd714 100644
--- a/src/model/scenery.js
+++ b/src/model/scenery.js
@@ -3,6 +3,7 @@ import StandardTrack from './standard-track';
import BezierTrack from './bezier-track';
import TrackObject from './track-object';
import Signal from './signal';
+import Route from './route';
export default class Scenery
{
@@ -67,6 +68,11 @@ export default class Scenery
return Switch.fromText(text);
case 'TrackObject':
return Scenery._parseTrackObject(text);
+ case 'Route':
+ return Route.fromText(text);
+ case 'Empty':
+ case 'EndRoute':
+ return null;
default:
console.warn(`Unknown object type: ${type}`);
return null;
@@ -91,10 +97,6 @@ export default class Scenery
}
static _parseTrackObject(text) {
- const prefabName = text.split(";", 4)[2];
- switch(prefabName) {
- default:
- return TrackObject.fromText(text);
if(Signal.isSignal(text)) {
return Signal.fromText(text);
} else {