Tracks color indication, slope calculations
+Added option to color the tracks by type or their slope *Slightly refactored TrackRenderer component *Fixed points calculations in StandardTrack to include track's slope
This commit is contained in:
parent
5c631c071b
commit
0b77a5a782
@ -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 (
|
||||
<SettingsContext.Provider value={{
|
||||
layers, setLayers
|
||||
layers, setLayers,
|
||||
trackColorMode, setTrackColorMode
|
||||
}}>
|
||||
{ props.children }
|
||||
</SettingsContext.Provider>
|
||||
|
||||
@ -5,7 +5,6 @@
|
||||
|
||||
.map svg path.track {
|
||||
stroke-width: 1.44px;
|
||||
stroke: #aaa;
|
||||
}
|
||||
|
||||
.map svg text {
|
||||
|
||||
@ -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 (
|
||||
<g>
|
||||
{defs}
|
||||
<path
|
||||
d={path}
|
||||
id={`track-${object.id}`}
|
||||
stroke={color}
|
||||
className="track"
|
||||
/>
|
||||
</g>
|
||||
);
|
||||
}
|
||||
|
||||
function getTrackPath(object) {
|
||||
switch (object.type) {
|
||||
case "StandardTrack":
|
||||
case "PointTrack":
|
||||
return <StandardTrackR {...props} />;
|
||||
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 <BezierTrackR {...props} />;
|
||||
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 (
|
||||
<path
|
||||
d={d}
|
||||
id={`track-${object.id}`}
|
||||
stroke={color}
|
||||
className="track"
|
||||
/>
|
||||
<defs>
|
||||
<linearGradient
|
||||
id={gradId}
|
||||
gradientUnits="userSpaceOnUse"
|
||||
x1={x1}
|
||||
y1={y1}
|
||||
x2={x2}
|
||||
y2={y2}
|
||||
>
|
||||
<stop offset="0%" stopColor={startColor} />
|
||||
<stop offset="100%" stopColor={endColor} />
|
||||
</linearGradient>
|
||||
</defs>
|
||||
);
|
||||
}
|
||||
|
||||
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 (
|
||||
<path
|
||||
d={d}
|
||||
id={`btrack-${object.id}`}
|
||||
stroke={color}
|
||||
className="track"
|
||||
/>
|
||||
);
|
||||
function getSlopeColor(slope) {
|
||||
const blue = Math.min(255, Math.max(0, 128 + Math.abs(slope * Constants.map.trackSlopeScale)));
|
||||
return `rgb(128, 128, ${blue})`;
|
||||
}
|
||||
28
src/components/sidemenu/SelTrackColorMode.js
Normal file
28
src/components/sidemenu/SelTrackColorMode.js
Normal file
@ -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 (
|
||||
<div className="track-color-mode-select">
|
||||
<label htmlFor="track-color-mode">Track Color Mode:</label><br />
|
||||
<select
|
||||
id="track-color-mode"
|
||||
value={trackColorMode}
|
||||
onChange={handleColorModeChange}
|
||||
>
|
||||
{Constants.trackColorModes.map((mode) => (
|
||||
<option key={mode.id} value={mode.id}>
|
||||
{mode.name}
|
||||
</option>
|
||||
))}
|
||||
</select>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@ -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() {
|
||||
<div className='side-menu-wrapper'>
|
||||
<div className='side-menu'>
|
||||
<LayersMenu />
|
||||
<SelTrackColorMode />
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
@ -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'
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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) {
|
||||
|
||||
Loading…
Reference in New Issue
Block a user