Add Track.getPointAtDist method and refactor StandardTrack._calcPoints()
This commit is contained in:
parent
ff3baa3c26
commit
94bfa7c060
@ -40,7 +40,7 @@ function InfoPopupSwitchItems(props) {
|
|||||||
|
|
||||||
function InfoPopupShapeItems(props) {
|
function InfoPopupShapeItems(props) {
|
||||||
const { track } = props;
|
const { track } = props;
|
||||||
if (track.type !== 'StandardTrack' || track.r === 0) return null;
|
if (track.r === 0) return null;
|
||||||
|
|
||||||
return <InfoPopupItem value={Math.abs(track.r)} label="Radius" options={{suffix: ' m', precision: 0}} />
|
return <InfoPopupItem value={Math.abs(track.r)} label="Radius" options={{suffix: ' m', precision: 0}} />
|
||||||
}
|
}
|
||||||
|
|||||||
@ -13,8 +13,15 @@ export default class BezierTrack extends Track
|
|||||||
middle: Vector3.zero(),
|
middle: Vector3.zero(),
|
||||||
};
|
};
|
||||||
|
|
||||||
constructor(id, start, control1, end, control2, rot, len, r, connections, id_station, start_slope, end_slope, id_isolation, prefab_name, maxspeed, derailspeed) {
|
constructor(id, start, control1, end, control2, connections, id_station, start_slope, end_slope, id_isolation, prefab_name, maxspeed, derailspeed) {
|
||||||
super(id, start, rot, len, r, connections, id_station, start_slope, end_slope, id_isolation, prefab_name, maxspeed, derailspeed, TrackSource.BEZIER);
|
const length = start.distance(end); // TODO: calculate more precise length
|
||||||
|
super(
|
||||||
|
id, start,
|
||||||
|
Vector3.zero(), // rotation
|
||||||
|
length,
|
||||||
|
0, // radius
|
||||||
|
connections, id_station, start_slope, end_slope, id_isolation, prefab_name, maxspeed, derailspeed, TrackSource.BEZIER,
|
||||||
|
);
|
||||||
|
|
||||||
Object.assign(this.points, {
|
Object.assign(this.points, {
|
||||||
start,
|
start,
|
||||||
@ -22,11 +29,10 @@ export default class BezierTrack extends Track
|
|||||||
end,
|
end,
|
||||||
control2: end.add(control2),
|
control2: end.add(control2),
|
||||||
});
|
});
|
||||||
// This is not the the actual middle point, but it's close enough
|
this.points.middle = this.getPointAtDist(length / 2);
|
||||||
this.points.middle = this._pointAtT(0.5);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
_pointAtT(t) {
|
_getPointAtT(t) {
|
||||||
const a1 = this.points.start.lerp(this.points.control1, t);
|
const a1 = this.points.start.lerp(this.points.control1, t);
|
||||||
const a2 = this.points.control1.lerp(this.points.control2, t);
|
const a2 = this.points.control1.lerp(this.points.control2, t);
|
||||||
const a3 = this.points.control2.lerp(this.points.end, t);
|
const a3 = this.points.control2.lerp(this.points.end, t);
|
||||||
@ -37,6 +43,12 @@ export default class BezierTrack extends Track
|
|||||||
return b1.lerp(b2, t);
|
return b1.lerp(b2, t);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getPointAtDist(dist, fromEnd = TrackConnectionEnd.START) {
|
||||||
|
if (fromEnd === TrackConnectionEnd.END) return this.getPointAtDist(this.len - dist, TrackConnectionEnd.START);
|
||||||
|
// TODO: This is just an approximation for a Bezier curve
|
||||||
|
return this._getPointAtT(dist / this.len);
|
||||||
|
}
|
||||||
|
|
||||||
getStartAngleXZ() {
|
getStartAngleXZ() {
|
||||||
return this.points.start.atanY(this.points.control1);
|
return this.points.start.atanY(this.points.control1);
|
||||||
}
|
}
|
||||||
@ -58,10 +70,6 @@ export default class BezierTrack extends Track
|
|||||||
Vector3.fromValuesArray(values, 6), // control1
|
Vector3.fromValuesArray(values, 6), // control1
|
||||||
Vector3.fromValuesArray(values, 9), // end
|
Vector3.fromValuesArray(values, 9), // end
|
||||||
Vector3.fromValuesArray(values, 12), // control2
|
Vector3.fromValuesArray(values, 12), // control2
|
||||||
// TODO: values below
|
|
||||||
Vector3.zero(),
|
|
||||||
0, // len ??
|
|
||||||
0, // r ??
|
|
||||||
connections,
|
connections,
|
||||||
values[17], // id_station
|
values[17], // id_station
|
||||||
...Track.slopesFromText(values[18]), // start_slope, end_slope
|
...Track.slopesFromText(values[18]), // start_slope, end_slope
|
||||||
|
|||||||
@ -3,13 +3,13 @@ import Track, {TrackSource} from "./track";
|
|||||||
import Vector3 from "../vector3";
|
import Vector3 from "../vector3";
|
||||||
import TrackConnection, {TrackConnectionEnd} from "../track-connection";
|
import TrackConnection, {TrackConnectionEnd} from "../track-connection";
|
||||||
import {ElectrificationStatus} from "../electrification-status";
|
import {ElectrificationStatus} from "../electrification-status";
|
||||||
|
import CurveHelper from "../../helpers/curveHelper";
|
||||||
|
|
||||||
export default class StandardTrack extends Track {
|
export default class StandardTrack extends Track {
|
||||||
type = "StandardTrack";
|
type = "StandardTrack";
|
||||||
points = {
|
points = {
|
||||||
start: Vector3.zero(),
|
start: Vector3.zero(),
|
||||||
end: Vector3.zero(),
|
end: Vector3.zero(),
|
||||||
circleCenter: Vector3.zero(),
|
|
||||||
middle: Vector3.zero(),
|
middle: Vector3.zero(),
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -18,6 +18,19 @@ export default class StandardTrack extends Track {
|
|||||||
this._calcPoints();
|
this._calcPoints();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_transformPoint(point) {
|
||||||
|
const rotRad = AngleHelper.rotationDegToRad(this.rot);
|
||||||
|
return point.rotate(rotRad).add(this.points.start);
|
||||||
|
}
|
||||||
|
|
||||||
|
getPointAtDist(dist, fromEnd = TrackConnectionEnd.START) {
|
||||||
|
if (fromEnd === TrackConnectionEnd.END) return this.getPointAtDist(this.len - dist, TrackConnectionEnd.START)
|
||||||
|
const curveEnd = CurveHelper.calculateCurveEndStandard(this.r, dist).endPos;
|
||||||
|
// TODO: Verify slope logic
|
||||||
|
curveEnd.y += (this.start_slope + this.end_slope) / 2000 * dist;
|
||||||
|
return this._transformPoint(curveEnd);
|
||||||
|
}
|
||||||
|
|
||||||
getStartAngleXZ() {
|
getStartAngleXZ() {
|
||||||
return AngleHelper.degToRad(this.rot.y);
|
return AngleHelper.degToRad(this.rot.y);
|
||||||
}
|
}
|
||||||
@ -25,10 +38,9 @@ export default class StandardTrack extends Track {
|
|||||||
getEndAngleXZ() {
|
getEndAngleXZ() {
|
||||||
const startAngle = AngleHelper.degToRad(this.rot.y);
|
const startAngle = AngleHelper.degToRad(this.rot.y);
|
||||||
|
|
||||||
if(this.r === 0) {
|
if (this.r === 0) return startAngle
|
||||||
return startAngle
|
|
||||||
}
|
|
||||||
|
|
||||||
|
// This is only correct for a flat arc on the XZ plane
|
||||||
return startAngle - this.len / this.r;
|
return startAngle - this.len / this.r;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -59,32 +71,9 @@ export default class StandardTrack extends Track {
|
|||||||
}
|
}
|
||||||
|
|
||||||
_calcPoints() {
|
_calcPoints() {
|
||||||
const rotRad = AngleHelper.degToRad(this.rot.y);
|
|
||||||
|
|
||||||
this.points.start = this.pos.clone();
|
this.points.start = this.pos.clone();
|
||||||
|
this.points.middle = this.getPointAtDist(this.len / 2, TrackConnectionEnd.START);
|
||||||
if (this.r === 0) {
|
this.points.end = this.getPointAtDist(this.len, TrackConnectionEnd.START);
|
||||||
this.points.end = this.pos.add(Vector3.fromAngleY(rotRad, this.len));
|
|
||||||
this.points.middle = this.points.start.lerp(this.points.end, 0.5);
|
|
||||||
this.points.circleCenter = this.pos.clone(); // default circle center
|
|
||||||
} else {
|
|
||||||
const centerAngle = rotRad + Math.PI / 2;
|
|
||||||
this.points.circleCenter = this.pos.sub(Vector3.fromAngleY(centerAngle, this.r));
|
|
||||||
|
|
||||||
const middleAngle = centerAngle - (this.len / this.r) / 2;
|
|
||||||
this.points.middle = this.points.circleCenter.add(Vector3.fromAngleY(middleAngle, this.r));
|
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
applyObject(scenery) {
|
applyObject(scenery) {
|
||||||
|
|||||||
@ -55,6 +55,10 @@ export default class Track extends SceneryObject {
|
|||||||
else return this.getEndAngleXZ();
|
else return this.getEndAngleXZ();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getPointAtDist(_dist, _fromEnd) {
|
||||||
|
throw new Error("getPointAtDist() must be implemented in subclass");
|
||||||
|
}
|
||||||
|
|
||||||
static slopesFromText(text) {
|
static slopesFromText(text) {
|
||||||
return text.split(",", 2).map((slope) => parseFloat(slope));
|
return text.split(",", 2).map((slope) => parseFloat(slope));
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user