diff --git a/src/components/SettingsManager.js b/src/components/SettingsManager.js index bac1464..98a9339 100644 --- a/src/components/SettingsManager.js +++ b/src/components/SettingsManager.js @@ -4,6 +4,7 @@ import Constants from "../helpers/constants"; export default function SettingsManager(props) { const [ layers, setLayers ] = useState([]); + const [ trackColorMode, setTrackColorMode ] = useState(Constants.trackColorModes[0].id); const [ settingsLoaded, setSettingsLoaded ] = useState(false); const loadLayersSettings = useCallback(() => { @@ -22,7 +23,8 @@ export default function SettingsManager(props) { return ( { props.children } diff --git a/src/components/map/Map.css b/src/components/map/Map.css index c32c2e8..66fe93d 100644 --- a/src/components/map/Map.css +++ b/src/components/map/Map.css @@ -5,7 +5,6 @@ .map svg path.track { stroke-width: 1.44px; - stroke: #aaa; } .map svg text { diff --git a/src/components/map/object-renderers/TrackRenderer.js b/src/components/map/object-renderers/TrackRenderer.js index a3c4666..2d0c03f 100644 --- a/src/components/map/object-renderers/TrackRenderer.js +++ b/src/components/map/object-renderers/TrackRenderer.js @@ -1,67 +1,101 @@ - +import { useContext } from "react"; +import SettingsContext from "../../../contexts/SettingsContext"; import Constants from "../../../helpers/constants"; export default function TrackRenderer(props) { - const { object } = props; + const { object } = props; + const { trackColorMode } = useContext(SettingsContext); + const path = getTrackPath(object); + const color = getTrackColor(object, trackColorMode); + const defs = getTrackDefs(object, trackColorMode); + + return ( + + {defs} + + + ); +} + +function getTrackPath(object) { switch (object.type) { case "StandardTrack": - case "PointTrack": - return ; + case "PointTrack": + const [x1, y1] = object.points.start.toSVGCoords(); + const [x2, y2] = object.points.end.toSVGCoords(); + const ra = Math.abs(object.r); + if (object.r < 0) { + return `M${x1},${y1} A${ra} ${ra} 0 0 1 ${x2},${y2}`; + } else if (object.r > 0) { + return `M${x2},${y2} A${ra} ${ra} 0 0 1 ${x1},${y1}`; + } else { + return `M${x1},${y1} L${x2},${y2}`; + } case "BezierTrack": - return ; + const [bx1, by1] = object.points.start.toSVGCoords(); + const [bcx1, bcy1] = object.points.control1.toSVGCoords(); + const [bx2, by2] = object.points.end.toSVGCoords(); + const [bcx2, bcy2] = object.points.control2.toSVGCoords(); + return `M${bx1},${by1} C${bcx1},${bcy1} ${bcx2},${bcy2} ${bx2},${by2}`; default: - console.warn(`No renderer component for track type: ${object.type}`); - return null; + console.warn(`TrackRenderer: Unsupported track type: ${object.type}`); } } -function StandardTrackR(props) { - const { object } = props; +function getTrackColor(object, trackColorMode) { + switch (trackColorMode) { + case "none": + default: + return "#aaa"; + + case "type": + switch (object.type) { + case "StandardTrack": + default: + return "#00a"; + case "PointTrack": + return "#0a0"; + case "BezierTrack": + return "#aa8"; + } + case "slope": + return `url(#track-slope-${object.id})`; + } +} + +function getTrackDefs(object, trackColorMode) { + if (trackColorMode !== "slope") return null; + const [x1, y1] = object.points.start.toSVGCoords(); const [x2, y2] = object.points.end.toSVGCoords(); - const ra = Math.abs(object.r); - - let d; - if (object.r < 0) { - d = `M${x1},${y1} A${ra} ${ra} 0 0 1 ${x2},${y2}`; - } else if (object.r > 0) { - d = `M${x2},${y2} A${ra} ${ra} 0 0 1 ${x1},${y1}`; - } else { - d = `M${x1},${y1} L${x2},${y2}`; - } - - const color = Constants.map.useTrackColors ? ( - object.r === 0 ? "rgb(0, 255, 255)" : "rgb(0, 0, 255)" - ) : undefined; - + const gradId = `track-slope-${object.id}`; + const startColor = getSlopeColor(object.start_slope); + const endColor = getSlopeColor(object.end_slope); + return ( - + + + + + + ); } -function BezierTrackR(props) { - const { object } = props; - - const [x1, y1] = object.points.start.toSVGCoords(); - const [cx1, cy1] = object.points.control1.toSVGCoords(); - const [x2, y2] = object.points.end.toSVGCoords(); - const [cx2, cy2] = object.points.control2.toSVGCoords(); - - const d = `M${x1},${y1} C${cx1},${cy1} ${cx2},${cy2} ${x2},${y2}`; - const color = Constants.map.useTrackColors ? "rgb(0, 255, 0)" : undefined; - - return ( - - ); -} +function getSlopeColor(slope) { + const blue = Math.min(255, Math.max(0, 128 + Math.abs(slope * Constants.map.trackSlopeScale))); + return `rgb(128, 128, ${blue})`; +} \ No newline at end of file diff --git a/src/components/sidemenu/SelTrackColorMode.js b/src/components/sidemenu/SelTrackColorMode.js new file mode 100644 index 0000000..20eb420 --- /dev/null +++ b/src/components/sidemenu/SelTrackColorMode.js @@ -0,0 +1,28 @@ +import { useContext } from "react"; +import SettingsContext from "../../contexts/SettingsContext"; +import Constants from "../../helpers/constants"; + +export default function SelTrackColorMode(props) { + const { trackColorMode, setTrackColorMode } = useContext(SettingsContext); + + const handleColorModeChange = (event) => { + setTrackColorMode(event.target.value); + }; + + return ( +
+
+ +
+ ); +} \ No newline at end of file diff --git a/src/components/sidemenu/SideMenu.js b/src/components/sidemenu/SideMenu.js index 0416e28..a9d6c63 100644 --- a/src/components/sidemenu/SideMenu.js +++ b/src/components/sidemenu/SideMenu.js @@ -2,6 +2,7 @@ import {useContext} from 'react'; import MainContext from '../../contexts/MainContext'; import './SideMenu.css'; import LayersMenu from './LayersMenu'; +import SelTrackColorMode from './SelTrackColorMode'; export default function SideMenu() { const { sideMenuOpen } = useContext(MainContext); @@ -14,6 +15,7 @@ export default function SideMenu() {
+
); diff --git a/src/helpers/constants.js b/src/helpers/constants.js index 8e889f0..da022e1 100644 --- a/src/helpers/constants.js +++ b/src/helpers/constants.js @@ -1,7 +1,7 @@ const Constants = { map: { - useTrackColors: false, zoomSensitivity: 0.002, + trackSlopeScale: 10, }, warnings: { all: false, // enable all warnings @@ -41,6 +41,20 @@ const Constants = { name: 'Routes', default: true, } + ], + trackColorModes: [ + { + id: 'none', + name: 'None', + }, + { + id: 'type', + name: 'Type', + }, + { + id: 'slope', + name: 'Slope' + } ] }; diff --git a/src/model/bezier-track.js b/src/model/bezier-track.js index a07fd0e..c51d952 100644 --- a/src/model/bezier-track.js +++ b/src/model/bezier-track.js @@ -11,8 +11,8 @@ export default class BezierTrack extends Track control2: Vector3.zero() }; - constructor(id, start, control1, end, control2, rot, len, r, previd, nextid, id_station, id_isolation, maxspeed, derailspeed) { - super(id, start, rot, len, r, previd, nextid, id_station, id_isolation, maxspeed, derailspeed); + constructor(id, start, control1, end, control2, rot, len, r, previd, nextid, id_station, start_slope, end_slope, id_isolation, maxspeed, derailspeed) { + super(id, start, rot, len, r, previd, nextid, id_station, start_slope, end_slope, id_isolation, maxspeed, derailspeed); Object.assign(this.points, { start, @@ -37,6 +37,7 @@ export default class BezierTrack extends Track values[15], // previd values[16], // nextid values[17], // id_station + ...Track.slopesFromText(values[18]), // start_slope, end_slope values[21], // id_isolation parseFloat(values[24]), // maxspeed parseFloat(values[25]) // derailspeed diff --git a/src/model/point-track.js b/src/model/point-track.js index 0f8e999..6f14d2b 100644 --- a/src/model/point-track.js +++ b/src/model/point-track.js @@ -10,12 +10,12 @@ export default class PointTrack extends Track end: Vector3.zero() }; - constructor(id, start, end, r, previd, nextid, id_station, id_isolation, maxspeed, derailspeed) { + constructor(id, start, end, r, previd, nextid, id_station, start_slope, end_slope, id_isolation, maxspeed, derailspeed) { const ry = AngleHelper.radToDeg(start.atanY(end)); const rot = new Vector3(0, ry, 0); // TODO: fix rx and rz = 0 // TODO: calculate length - super(id, start, rot, null, r, previd, nextid, id_station, id_isolation, maxspeed, derailspeed); + super(id, start, rot, null, r, previd, nextid, id_station, start_slope, end_slope, id_isolation, maxspeed, derailspeed); Object.assign(this.points, { start, end diff --git a/src/model/standard-track.js b/src/model/standard-track.js index 5aa654a..d523c41 100644 --- a/src/model/standard-track.js +++ b/src/model/standard-track.js @@ -11,8 +11,8 @@ export default class StandardTrack extends Track circleCenter: Vector3.zero() }; - constructor(id, start, rot, len, r, previd, nextid, id_station, id_isolation, maxspeed, derailspeed) { - super(id, start, rot, len, r, previd, nextid, id_station, id_isolation, maxspeed, derailspeed); + constructor(id, start, rot, len, r, previd, nextid, id_station, start_slope, end_slope, id_isolation, maxspeed, derailspeed) { + super(id, start, rot, len, r, previd, nextid, id_station, start_slope, end_slope, id_isolation, maxspeed, derailspeed); this._calcPoints(); } @@ -27,6 +27,7 @@ export default class StandardTrack extends Track values[11], // previd values[12], // nextid values[13], // id_station + ...Track.slopesFromText(values[14]), // start_slope, end_slope values[17], // id_isolation parseFloat(values[20]), // maxspeed parseFloat(values[21]) // derailspeed @@ -48,5 +49,13 @@ export default class StandardTrack extends Track const endAngle = centerAngle - this.len / this.r; this.points.end = this.points.circleCenter.add(Vector3.fromAngleY(endAngle, this.r)); } + + // adjust end point by the slope + if (this.end_slope !== 0) { + const startHeightDiff = this.start_slope * this.len / 1000; + const endHeightDiff = this.end_slope * this.len / 1000; + + this.points.end.y += startHeightDiff + (endHeightDiff - startHeightDiff) / 2; + } } } diff --git a/src/model/switch.js b/src/model/switch.js index 1d41187..dd83370 100644 --- a/src/model/switch.js +++ b/src/model/switch.js @@ -122,6 +122,8 @@ export default class Switch extends SceneryObject { from, to, this.id_switch, + 0, // start_slope + 0, // end_slope this.id_isolation, this.maxspeed, this.derailspeed diff --git a/src/model/track.js b/src/model/track.js index 8f3c619..c078dbf 100644 --- a/src/model/track.js +++ b/src/model/track.js @@ -9,17 +9,27 @@ export default class Track extends SceneryObject { derailspeed; category = "tracks"; type = "Track"; - outs = []; + previd; + nextid; + prevTrack = null; + nextTrack = null; + start_slope; + end_slope; - constructor(id, pos, rot, len, r, previd, nextid, id_station, id_isolation, maxspeed, derailspeed) { + constructor(id, pos, rot, len, r, previd, nextid, id_station, start_slope, end_slope, id_isolation, maxspeed, derailspeed) { super(id, pos, rot); Object.assign(this, { len, r, - id_station, id_isolation, + previd, nextid, + id_station, + start_slope, end_slope, + id_isolation, maxspeed, derailspeed }); + } - this.outs = [previd, nextid]; + static slopesFromText(text) { + return text.split(",", 2); } getCloserEndPos(pos) {