Eclipse SUMO - Simulation of Urban MObility
Loading...
Searching...
No Matches
MSTrainHelper.cpp
Go to the documentation of this file.
1/****************************************************************************/
2// Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
3// Copyright (C) 2001-2025 German Aerospace Center (DLR) and others.
4// This program and the accompanying materials are made available under the
5// terms of the Eclipse Public License 2.0 which is available at
6// https://www.eclipse.org/legal/epl-2.0/
7// This Source Code may also be made available under the following Secondary
8// Licenses when the conditions for such availability set forth in the Eclipse
9// Public License 2.0 are satisfied: GNU General Public License, version 2
10// or later which is available at
11// https://www.gnu.org/licenses/old-licenses/gpl-2.0-standalone.html
12// SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-or-later
13/****************************************************************************/
18// A class that helps computing positions of a train's carriages.
19/****************************************************************************/
20#include <config.h>
21
22#include <microsim/MSLane.h>
24#include <microsim/MSVehicle.h>
25#include <microsim/MSEdge.h>
26#include "MSTrainHelper.h"
27
28#define MIN_SCALED_CARRIAGE_LENGTH 5.
29
31
32// ===========================================================================
33// method definitions
34// ===========================================================================
35void
36MSTrainHelper::computeTrainDimensions(double exaggeration, bool secondaryShape, double scaledLength, int vehicleQuality) {
37 const MSVehicleType& vtype = myTrain->getVehicleType();
38 const double laneFactor = (myTrain->getLane() != nullptr
39 ? myTrain->getLane()->getLengthGeometryFactor(secondaryShape)
40 : (myTrain->getEdge()->getLanes().size() > 0 ? myTrain->getEdge()->getLanes()[0]->getLengthGeometryFactor(secondaryShape) : 1));
41 double totalLength = vtype.getLength();
42 const double geometryScale = scaledLength / totalLength;
43 myUpscaleLength = getUpscaleLength(exaggeration, totalLength, vtype.getWidth(), vehicleQuality);
46 if (myLocomotiveLength == 0) {
48 }
49 const double minLength = MIN2(myLocomotiveLength, myDefaultLength);
50 const double minScaledLength = MIN2(MIN_SCALED_CARRIAGE_LENGTH, minLength);
51 myUnscale = geometryScale == 1 && laneFactor != 1;
52 if (geometryScale < 1 && minLength * geometryScale < minScaledLength) {
53 const double rescaleSmall = minScaledLength / (minLength * geometryScale);
54 myLocomotiveLength *= rescaleSmall;
55 myDefaultLength *= rescaleSmall;
56 }
58 myLength = totalLength * myUpscaleLength;
59 myHalfWidth = 0.5 * vtype.getWidth() * exaggeration;
60 myNumCarriages = MAX2(1, 1 + (int)((myLength - myLocomotiveLength) / (myDefaultLength + myCarriageGap) + 0.5)); // Round to closest integer.
61 if (myUpscaleLength > 1 && vehicleQuality != 4) {
62 // at high zoom, it doesn't help to draw many carriages)
65 }
66 assert(myNumCarriages > 0);
67 if (myNumCarriages == 1) {
68 myCarriageGap = 0;
69 }
77 }
79}
80
81
82void
83MSTrainHelper::computeCarriages(bool reversed, bool secondaryShape) {
84 myCarriages.clear();
85
86 const MSLane* lane = myTrain->getLane(); // Lane on which the carriage's front is situated.
87 int furtherIndex = 0;
88 const MSLane* backLane = lane; // Lane on which the carriage's back is situated.
89 int backFurtherIndex = furtherIndex;
90 // Offsets of front and back parts of a carriage.
91 double carriageOffset = myTrain->getPositionOnLane();
93 // This still produces some artifacts when not fully on the current lane.
94 carriageOffset = MIN2(carriageOffset + myTrain->getLength(), lane->getLength());
95 }
96 const double unscale = myUnscale ? 1. / lane->getLengthGeometryFactor() : 1.;
97 double carriageBackOffset = carriageOffset - myFirstCarriageLength * unscale;
98
99 myFirstCarriageNo = 0; // default case - we're going forwards
101 if (myIsReversed) {
103 if (myNumCarriages > 1) {
104 carriageBackOffset = carriageOffset - myCarriageLength;
105 }
106 }
108 myFirstCarriageNo = -1; // don't draw locomotive
109 }
110
112 || (myTrain->getVClass() & (SVC_RAIL_ELECTRIC | SVC_RAIL_FAST | SVC_RAIL)) == 0 ? 0 : 1;
113
114 const double lateralOffset = (myTrain->isParking() && myTrain->getNextStopParameter()->posLat == INVALID_DOUBLE
115 ? (myTrain->getLane()->getWidth() * (MSGlobals::gLefthand ? -1 : 1))
117
118 for (int i = 0; i < myNumCarriages; ++i) {
119 Carriage* carriage = new Carriage();
120 if (i == myFirstCarriageNo) {
121 if (myFirstCarriageNo > 0) {
122 // Previous loop iteration has adjusted backpos for a normal carriage so have to correct
123 carriageBackOffset += myCarriageLengthWithGap;
124 carriageBackOffset -= myFirstCarriageLength + myCarriageGap;
125 }
126 }
127 while (carriageOffset < 0) {
128 const MSLane* prev = myTrain->getPreviousLane(lane, furtherIndex);
129 if (prev != lane) {
130 carriageOffset += prev->getLength();
131 } else {
132 break;
133 }
134 lane = prev;
135 }
136 while (carriageBackOffset < 0) {
137 const MSLane* prev = myTrain->getPreviousLane(backLane, backFurtherIndex);
138 if (prev != backLane) {
139 if (myUnscale) {
140 carriageBackOffset *= backLane->getLengthGeometryFactor() / prev->getLengthGeometryFactor();
141 }
142 carriageBackOffset += prev->getLength();
143 } else {
144 break;
145 }
146 backLane = prev;
147 }
148 carriage->front = lane->getShape(secondaryShape).positionAtOffset2D(carriageOffset * lane->getLengthGeometryFactor(secondaryShape), lateralOffset, true);
149 carriage->back = backLane->getShape(secondaryShape).positionAtOffset2D(carriageBackOffset * backLane->getLengthGeometryFactor(secondaryShape), lateralOffset, true);
150 myCarriages.push_back(carriage);
151 lane = backLane;
152 furtherIndex = backFurtherIndex;
153 carriageOffset = carriageBackOffset - myCarriageGap;
154 carriageBackOffset -= myCarriageLengthWithGap * unscale;
155 }
156}
157
158
159void
161 for (Carriage* carriage : myCarriages) {
162 Position dir = carriage->front - carriage->back;
163 const double carriageLength = dir.length2D();
164 if (carriageLength > 0.0) {
165 dir.norm2D();
166 for (int j = 1; j <= myCarriageDoors; j++) {
167 const double doorOffset = j * carriageLength / (myCarriageDoors + 1);
168 carriage->doorPositions.push_back(carriage->front - dir * doorOffset);
169 }
170 }
171 }
172}
173
174
175void
176MSTrainHelper::computeUnboardingPositions(double passengerRadius, std::vector<Position>& unboardingPositions) {
177 passengerRadius += PEDESTRIAN_RADIUS_EXTRA_TOLERANCE;
178 for (Carriage* carriage : myCarriages) {
179 Position dir = carriage->front - carriage->back;
180 const double carriageLength = dir.length2D();
181 if (carriageLength > 0.0) {
182 dir.norm2D();
183 const Position perp = Position(-dir.y(), dir.x());
184 double nbrLongitudinalCells, longitudinalOffset;
185 longitudinalOffset = std::modf((carriageLength - 2.0 * passengerRadius) / (2.0 * passengerRadius), &nbrLongitudinalCells);
186 double nbrLateralCells, lateralOffset;
187 lateralOffset = std::modf((myHalfWidth * 2.0 - 2.0 * passengerRadius) / (2.0 * passengerRadius), &nbrLateralCells);
188 const Position gridOrigin = carriage->back + dir * (passengerRadius + 0.5 * longitudinalOffset) - perp * (myHalfWidth - passengerRadius - 0.5 * lateralOffset);
189 for (unsigned int i = 0; i <= (unsigned int)nbrLongitudinalCells; i++) {
190 for (unsigned int j = 0; j <= (unsigned int)nbrLateralCells; j++) {
191 carriage->unboardingPositions.push_back(gridOrigin + dir * i * 2.0 * passengerRadius + perp * j * 2.0 * passengerRadius);
192 }
193 }
194 }
195 std::copy(carriage->unboardingPositions.begin(), carriage->unboardingPositions.end(), std::back_inserter(unboardingPositions));
196 }
197 // Shuffle the positions upstream so that we don't have to sample later on, just pop the last element.
198 RandHelper::shuffle(unboardingPositions);
199}
200
201
202double
203MSTrainHelper::getUpscaleLength(double upscale, double length, double width, int vehicleQuality) {
204 if (upscale > 1 && length > 5 && width < 5 && vehicleQuality != 4) {
205 return MAX2(1.0, upscale * 5 / length);
206 } else {
207 return upscale;
208 }
209}
#define MIN_SCALED_CARRIAGE_LENGTH
@ SVC_RAIL
vehicle is a not electrified rail
@ SVC_RAIL_FAST
vehicle that is allowed to drive on high-speed rail tracks
@ SVC_RAIL_ELECTRIC
rail vehicle that requires electrified tracks
const double INVALID_DOUBLE
invalid double
Definition StdDefs.h:68
T MIN2(T a, T b)
Definition StdDefs.h:80
T MAX2(T a, T b)
Definition StdDefs.h:86
bool isReversed() const
Returns whether the logical state of the vehicle is reversed - for drawing.
const SUMOVehicleParameter::Stop * getNextStopParameter() const
return parameters for the next stop (SUMOVehicle Interface)
double getLength() const
Returns the vehicle's length.
bool isParking() const
Returns whether the vehicle is parking.
const MSEdge * getEdge() const
Returns the edge the vehicle is currently at.
SUMOVehicleClass getVClass() const
Returns the vehicle's access class.
const MSVehicleType & getVehicleType() const
Returns the vehicle's type definition.
const std::vector< MSLane * > & getLanes() const
Returns this edge's lanes.
Definition MSEdge.h:168
static bool gLefthand
Whether lefthand-drive is being simulated.
Definition MSGlobals.h:174
Representation of a lane in the micro simulation.
Definition MSLane.h:84
virtual double getLengthGeometryFactor(bool) const
Definition MSLane.h:290
double getLength() const
Returns the lane's length.
Definition MSLane.h:611
virtual const PositionVector & getShape(bool) const
Definition MSLane.h:294
double getWidth() const
Returns the lane's width.
Definition MSLane.h:640
double myFirstCarriageLength
void computeTrainDimensions(double exaggeration, bool secondaryShape, double scaledLength, int vehicleQuality)
const MSVehicle * myTrain
static const double PEDESTRIAN_RADIUS_EXTRA_TOLERANCE
small extra tolerance used to avoid constraint violations
std::vector< Carriage * > myCarriages
void computeDoorPositions()
compute door positions on demand and fills the carriage structures
double myLocomotiveLength
double myCarriageLengthWithGap
void computeUnboardingPositions(double passengerRadius, std::vector< Position > &unboardingPositions)
compute unboarding positions on demand and fills the carriage structures
double myDefaultLength
int myFirstPassengerCarriage
double myCarriageLength
double getUpscaleLength() const
double myUpscaleLength
void computeCarriages(bool reversed, bool secondaryShape)
const MSLane * getPreviousLane(const MSLane *current, int &furtherIndex) const
MSAbstractLaneChangeModel & getLaneChangeModel()
const MSLane * getLane() const
Returns the lane the vehicle is on.
Definition MSVehicle.h:581
double getLateralPositionOnLane() const
Get the vehicle's lateral position on the lane.
Definition MSVehicle.h:413
double getPositionOnLane() const
Get the vehicle's position along the lane.
Definition MSVehicle.h:374
The car-following model and parameter.
double getWidth() const
Get the width which vehicles of this class shall have when being drawn.
double getLength() const
Get vehicle's length [m].
const SUMOVTypeParameter & getParameter() const
A point in 2D or 3D with translation and scaling methods.
Definition Position.h:37
void norm2D()
Normalizes the given vector.
Definition Position.h:179
double x() const
Returns the x-position.
Definition Position.h:52
double length2D() const
Computes the length of the given vector neglecting the z coordinate.
Definition Position.h:174
double y() const
Returns the y-position.
Definition Position.h:57
Position positionAtOffset2D(double pos, double lateralOffset=0, bool extrapolateBeyond=false) const
Returns the position at the given length.
static void shuffle(std::vector< T > &v, SumoRNG *rng=nullptr)
Definition RandHelper.h:241
double locomotiveLength
the length of the locomotive
double carriageLength
the length of train carriages
int carriageDoors
the number of doors per carriage
double carriageGap
the length of the gap between carriages
double posLat
the lateral offset when stopping