Added signs layer

+Added SignRenderer and sign parsing. For now only the W5 sign is defined
This commit is contained in:
izawartka 2025-06-10 22:35:46 +02:00
parent 2408fda0c9
commit 95317798e5
9 changed files with 121 additions and 2 deletions

View File

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg width="100mm" height="100mm" version="1.1" viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg">
<g>
<path d="m50 8c-18.73 0-34 15.27-34 34v4h68v-4c0-18.73-15.27-34-34-34zm0 8c13.036 0 23.675 9.5208 25.6 22h-51.199c1.9247-12.479 12.564-22 25.6-22z" color="#000000" fill-rule="evenodd" style="-inkscape-stroke:none"/>
<path d="m50 39a4 4 0 0 0-4 4v45a4 4 0 0 0 4 4 4 4 0 0 0 4-4v-45a4 4 0 0 0-4-4z" color="#000000"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 482 B

View File

@ -63,4 +63,8 @@
.map svg g.signalbox text {
fill: #eee;
font-size: 4px;
}
}
.map svg g.sign path {
fill: #eee;
}

View File

@ -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',

View File

@ -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 (
<g className="sign" transform={`translate(${x}, ${y}) rotate(${object.rot.y}) translate(${offX}, ${offY})`}>
<ReactSVG
src={`/assets/signs/${object.def.icon}`}
wrapper='svg'
beforeInjection={(svg) => {
svg.setAttribute('width', '1mm');
svg.setAttribute('height', '1mm');
}}
/>
</g>
);
}

View File

@ -22,6 +22,8 @@ export default function SceneryInfoView({ scenery }) {
}
function SceneryInfoViewItem({ label, value, isLink = false }) {
if(!value) value = 'No data';
return (
<tr>
<td className="label">{label}</td>

View File

@ -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',

View File

@ -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;

View File

@ -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);

53
src/model/sign.js Normal file
View File

@ -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];
}
}