From 95317798e5da8c2e3fee4cb314ff8c368e2efa95 Mon Sep 17 00:00:00 2001 From: izawartka <59137928+izawartka@users.noreply.github.com> Date: Tue, 10 Jun 2025 22:35:46 +0200 Subject: [PATCH] Added signs layer +Added SignRenderer and sign parsing. For now only the W5 sign is defined --- public/assets/signs/w5.svg | 7 +++ src/components/map/Map.css | 6 ++- src/components/map/ObjectsRenderQueue.js | 8 +++ .../map/object-renderers/SignRenderer.js | 25 +++++++++ .../scenery-info-dialog/SceneryInfoView.js | 2 + src/helpers/constants.js | 6 +++ src/model/defined-signs.js | 11 ++++ src/model/scenery.js | 5 +- src/model/sign.js | 53 +++++++++++++++++++ 9 files changed, 121 insertions(+), 2 deletions(-) create mode 100644 public/assets/signs/w5.svg create mode 100644 src/components/map/object-renderers/SignRenderer.js create mode 100644 src/model/defined-signs.js create mode 100644 src/model/sign.js diff --git a/public/assets/signs/w5.svg b/public/assets/signs/w5.svg new file mode 100644 index 0000000..8955e2e --- /dev/null +++ b/public/assets/signs/w5.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/src/components/map/Map.css b/src/components/map/Map.css index a62a4d9..82a7f8b 100644 --- a/src/components/map/Map.css +++ b/src/components/map/Map.css @@ -63,4 +63,8 @@ .map svg g.signalbox text { fill: #eee; font-size: 4px; -} \ No newline at end of file +} + +.map svg g.sign path { + fill: #eee; +} diff --git a/src/components/map/ObjectsRenderQueue.js b/src/components/map/ObjectsRenderQueue.js index f1d9134..560eb17 100644 --- a/src/components/map/ObjectsRenderQueue.js +++ b/src/components/map/ObjectsRenderQueue.js @@ -5,6 +5,7 @@ import TrackObjectRenderer from './object-renderers/TrackObjectRenderer'; import SignalRenderer from './object-renderers/SignalRenderer'; import RouteRenderer from './object-renderers/RouteRenderer'; import SignalBoxRenderer from './object-renderers/SignalBoxRenderer'; +import SignRenderer from './object-renderers/SignRenderer'; const ObjectRendererQueue = [ { @@ -26,6 +27,13 @@ const ObjectRendererQueue = [ 'renderer': SwitchNameRenderer, 'cond': (layers) => layers['switches-names'] }, + { + 'name': 'signs', + 'category': 'track-objects', + 'type': 'Sign', + 'renderer': SignRenderer, + 'cond': (layers) => layers['signs'] + }, { 'name': 'signals', 'category': 'track-objects', diff --git a/src/components/map/object-renderers/SignRenderer.js b/src/components/map/object-renderers/SignRenderer.js new file mode 100644 index 0000000..d6df35e --- /dev/null +++ b/src/components/map/object-renderers/SignRenderer.js @@ -0,0 +1,25 @@ +import { ReactSVG } from 'react-svg' + +export default function SignRenderer(props) { + const { object } = props; + if(!object.def) return null; + + const [x, y] = object.pos.toSVGCoords(); + + const offX = -1.89 + (object.def.offsetX || 0); + const offY = -1.89 + (object.def.offsetY || 0); + + return ( + + { + svg.setAttribute('width', '1mm'); + svg.setAttribute('height', '1mm'); + }} + /> + + ); +} diff --git a/src/components/scenery-info-dialog/SceneryInfoView.js b/src/components/scenery-info-dialog/SceneryInfoView.js index 8ee4f3d..87963d2 100644 --- a/src/components/scenery-info-dialog/SceneryInfoView.js +++ b/src/components/scenery-info-dialog/SceneryInfoView.js @@ -22,6 +22,8 @@ export default function SceneryInfoView({ scenery }) { } function SceneryInfoViewItem({ label, value, isLink = false }) { + if(!value) value = 'No data'; + return ( {label} diff --git a/src/helpers/constants.js b/src/helpers/constants.js index 0a85c17..c170048 100644 --- a/src/helpers/constants.js +++ b/src/helpers/constants.js @@ -23,6 +23,7 @@ const Constants = { switchNoModel: true, signalBoxUndefinedPrefabName: true, invalidSceneryInfoVersion: true, + signUndefinedPrefabName: true, }, errors: { invalidSceneryInfo: true @@ -53,6 +54,11 @@ const Constants = { name: 'Signals', default: true, }, + { + id: 'signs', + name: 'Signs', + default: true, + }, { id: 'signalboxes', name: 'Signal boxes', diff --git a/src/model/defined-signs.js b/src/model/defined-signs.js new file mode 100644 index 0000000..71184e3 --- /dev/null +++ b/src/model/defined-signs.js @@ -0,0 +1,11 @@ +// remember to place sign_w1X before sign_w1 etc. + +const DefinedSigns = { + "sign_w5": { + "name": "W5", + "icon": "w5.svg", + "offsetY": -1.4364 + } +}; + +export default DefinedSigns; \ No newline at end of file diff --git a/src/model/scenery.js b/src/model/scenery.js index e498255..7242352 100644 --- a/src/model/scenery.js +++ b/src/model/scenery.js @@ -9,6 +9,7 @@ import SceneryParserLog from './scenery-parser-log'; import SignalBox from './signalbox'; import Constants from '../helpers/constants'; import SceneryInfo from './scenery-info'; +import Sign from './sign'; /* TODO: move parsers to another static class @@ -164,7 +165,9 @@ export default class Scenery } static _parseTrackObject(text) { - if(Signal.isSignal(text)) { + if(Sign.isSign(text)) { + return Sign.fromText(text); + } else if(Signal.isSignal(text)) { return Signal.fromText(text); } else { return TrackObject.fromText(text); diff --git a/src/model/sign.js b/src/model/sign.js new file mode 100644 index 0000000..9eb33d5 --- /dev/null +++ b/src/model/sign.js @@ -0,0 +1,53 @@ +import DefinedSigns from "./defined-signs"; +import SceneryParserLog from "./scenery-parser-log"; +import TrackObject from "./track-object"; +import Vector3 from "./vector3"; + +export default class Sign extends TrackObject { + type = "Sign"; + def; + + constructor(id, prefab_name, pos, rot, track_id, name) { + super(id, prefab_name, pos, rot, track_id, name); + + this.def = Sign.getDef(name, prefab_name); + } + + /* + Check if a TrackObject text is a Sign. + @param {string} text - The text representation of the TrackObject. + @returns {boolean} - Returns true if the text represents a Sign, false otherwise. + @static + @memberof Sign + */ + static isSign(text) { + const values = text.split(";"); + + const prefabInfo = values[2]?.trim() || ""; + return prefabInfo.startsWith("sign_"); + } + + static fromText(text) { + const values = text.split(";"); + const sign = new Sign( + values[1], // id + values[2], // prefab_name + Vector3.fromValuesArray(values, 3), // pos + Vector3.fromValuesArray(values, 6), // rot + values[9], // track_id + values[11], // name + ); + + return sign; + } + + static getDef(name, prefabName) { + const key = Object.keys(DefinedSigns).find(k => prefabName.startsWith(k)); + if (!key) { + SceneryParserLog.warn('signUndefinedPrefabName', `Sign ${name} has an undefined prefab name ${prefabName}`); + return null; + } + + return DefinedSigns[key]; + } +} \ No newline at end of file