Skip to content

Commit

Permalink
Refactored train drawing logic to be reusable elsewhere.
Browse files Browse the repository at this point in the history
  • Loading branch information
bcoueraud87 committed Feb 9, 2024
1 parent 05814e7 commit cd28c30
Show file tree
Hide file tree
Showing 7 changed files with 385 additions and 166 deletions.
177 changes: 22 additions & 155 deletions src/guisim/GUIVehicle.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -57,9 +57,9 @@
#include <microsim/devices/MSDevice_BTreceiver.h>
#include <microsim/devices/MSDevice_ElecHybrid.h>
#include <microsim/devices/MSDevice_Battery.h>
#include <microsim/transportables/MSTrainHelper.h>
#include <gui/GUIApplicationWindow.h>
#include <gui/GUIGlobals.h>

#include "GUIVehicle.h"
#include "GUIPerson.h"
#include "GUIContainer.h"
Expand Down Expand Up @@ -309,61 +309,23 @@ GUIVehicle::drawAction_drawLinkItems(const GUIVisualizationSettings& s) const {

void
GUIVehicle::drawAction_drawCarriageClass(const GUIVisualizationSettings& s, bool asImage) const {
const bool s2 = s.secondaryShape;
RGBColor current = GLHelper::getColor();
RGBColor darker = current.changedBrightness(-51);
const double exaggeration = (s.vehicleSize.getExaggeration(s, this)
* s.vehicleScaler.getScheme().getColor(getScaleValue(s, s.vehicleScaler.getActive())));
const double totalLength = getVType().getLength();
double upscaleLength = exaggeration;
if (exaggeration > 1 && totalLength > 5) {
// reduce the length/width ratio because this is not useful at high zoom
const double widthLengthFactor = totalLength / 5;
const double shrinkFactor = MIN2(widthLengthFactor, sqrt(upscaleLength));
upscaleLength /= shrinkFactor;
}
const double locomotiveLength = getVehicleType().getParameter().locomotiveLength * upscaleLength;
if (exaggeration == 0) {
return;
}
const double defaultLength = getVehicleType().getParameter().carriageLength * upscaleLength;
const double carriageGap = getVehicleType().getParameter().carriageGap * upscaleLength;
const double length = totalLength * upscaleLength;
const double halfWidth = getVehicleType().getWidth() / 2.0 * exaggeration;
GLHelper::popMatrix(); // undo initial translation and rotation
const double xCornerCut = 0.3 * exaggeration;
const double yCornerCut = 0.4 * exaggeration;
// round to closest integer
const int numCarriages = MAX2(1, 1 + (int)((length - locomotiveLength) / (defaultLength + carriageGap) + 0.5));
assert(numCarriages > 0);
double carriageLengthWithGap = length / numCarriages;
double carriageLength = carriageLengthWithGap - carriageGap;
double firstCarriageLength = carriageLength;
if (defaultLength != locomotiveLength && numCarriages > 1) {
firstCarriageLength = locomotiveLength;
carriageLengthWithGap = (length - locomotiveLength) / (numCarriages - 1);
carriageLength = carriageLengthWithGap - carriageGap;
}
const int firstPassengerCarriage = defaultLength == locomotiveLength || numCarriages == 1
// bool reversed =
MSTrainHelper trainHelper(this, isReversed() && s.drawReversed, s.secondaryShape);
int numCarriages = trainHelper.getNumCarriages();
const int firstPassengerCarriage = trainHelper.getDefaultLength() == trainHelper.getLocomotiveLength() || numCarriages == 1
|| (getVClass() & (SVC_RAIL_ELECTRIC | SVC_RAIL_FAST | SVC_RAIL)) == 0 ? 0 : 1;
const int noPersonsBackCarriages = (getVehicleType().getGuiShape() == SUMOVehicleShape::TRUCK_SEMITRAILER || getVehicleType().getGuiShape() == SUMOVehicleShape::TRUCK_1TRAILER) && numCarriages > 1 ? 1 : 0;
const int firstContainerCarriage = numCarriages == 1 || getVehicleType().getGuiShape() == SUMOVehicleShape::TRUCK_1TRAILER ? 0 : 1;
const int seatsPerCarriage = (int)ceil(getVType().getPersonCapacity() / (numCarriages - firstPassengerCarriage - noPersonsBackCarriages));
const int containersPerCarriage = (int)ceil(getVType().getContainerCapacity() / (numCarriages - firstContainerCarriage));
// lane on which the carriage front is situated
MSLane* lane = myLane;
int furtherIndex = 0;
// lane on which the carriage back is situated
MSLane* backLane = myLane;
int backFurtherIndex = furtherIndex;
// offsets of front and back
double carriageOffset = myState.pos();
if (getLaneChangeModel().isOpposite()) {
// @note this still produces some artifacts while not fully on the current lane
carriageOffset = MIN2(carriageOffset + getLength(), lane->getLength());
}
double carriageBackOffset = carriageOffset - firstCarriageLength;
// handle seats
// Handle seats.
int requiredSeats = getNumPassengers();
int requiredPositions = getNumContainers();
if (requiredSeats > 0) {
Expand All @@ -372,65 +334,24 @@ GUIVehicle::drawAction_drawCarriageClass(const GUIVisualizationSettings& s, bool
if (requiredPositions > 0) {
myContainerPositions.clear();
}
GLHelper::popMatrix(); // undo initial translation and rotation
const double xCornerCut = 0.3 * exaggeration;
const double yCornerCut = 0.4 * exaggeration;
Position front, back;
double angle = 0.;
// position parking vehicle beside the road or track
const double lateralOffset = (isParking() && getNextStopParameter()->posLat == INVALID_DOUBLE
? (getLane()->getWidth() * (MSGlobals::gLefthand ? -1 : 1))
: -getLateralPositionOnLane());

// draw individual carriages
double curCLength = firstCarriageLength;
int firstCarriageNo = 0; // default case - we're going forwards
const bool reversed = drawReversed(s) || getLaneChangeModel().isOpposite();
if (reversed) {
firstCarriageNo = numCarriages - 1;
if (numCarriages > 1) {
carriageBackOffset = carriageOffset - carriageLength;
}
}

//std::cout << SIMTIME << " veh=" << getID() << " curCLength=" << curCLength << " loc=" << locomotiveLength << " car=" << carriageLength << " tlen=" << totalLength << " len=" << length << "\n";
double angle = 0.0;
double curCLength = trainHelper.getFirstCarriageLength();
std::vector<MSTrainHelper::Carriage*> carriages = trainHelper.getCarriages();
for (int i = 0; i < numCarriages; ++i) {
if (i == firstCarriageNo) {
curCLength = firstCarriageLength;
if (firstCarriageNo > 0) {
// previous loop iteration has adjusted backpos for a normal carriage so have to correct
carriageBackOffset += carriageLengthWithGap;
carriageBackOffset -= firstCarriageLength + carriageGap;
}
} else {
curCLength = carriageLength;
}
while (carriageOffset < 0) {
MSLane* prev = getPreviousLane(lane, furtherIndex);
if (prev != lane) {
carriageOffset += prev->getLength();
} else {
// no lane available for drawing.
carriageOffset = 0;
}
lane = prev;
}
while (carriageBackOffset < 0) {
MSLane* prev = getPreviousLane(backLane, backFurtherIndex);
if (prev != backLane) {
carriageBackOffset += prev->getLength();
} else {
// no lane available for drawing.
carriageBackOffset = 0;
}
backLane = prev;
}
front = lane->getShape(s2).positionAtOffset(carriageOffset * lane->getLengthGeometryFactor(s2), lateralOffset);
back = backLane->getShape(s2).positionAtOffset(carriageBackOffset * lane->getLengthGeometryFactor(s2), lateralOffset);
front = carriages[i]->front;
back = carriages[i]->back;
if (front == back) {
// no place for drawing available
// No place for drawing available.
continue;
}
const double drawnCarriageLength = front.distanceTo2D(back);
angle = atan2((front.x() - back.x()), (back.y() - front.y())) * (double) 180.0 / (double) M_PI;
// if we are in reverse 'first' carriages are drawn last so the >= test doesn't work
const bool reversed = trainHelper.isReversed();
if (reversed) {
if (i <= numCarriages - firstPassengerCarriage) {
computeSeats(back, front, SUMO_const_waitingPersonWidth, seatsPerCarriage, exaggeration, requiredSeats, mySeatPositions);
Expand All @@ -446,22 +367,24 @@ GUIVehicle::drawAction_drawCarriageClass(const GUIVisualizationSettings& s, bool
computeSeats(front, back, SUMO_const_waitingContainerWidth, containersPerCarriage, exaggeration, requiredPositions, myContainerPositions);
}
}
curCLength = (i == trainHelper.getFirstCarriageNo() ? trainHelper.getFirstCarriageLength() : trainHelper.getCarriageLength());
GLHelper::pushMatrix();
glTranslated(front.x(), front.y(), getType());
glRotated(angle, 0, 0, 1);
double halfWidth = trainHelper.getHalfWidth();
if (!asImage || !GUIBaseVehicleHelper::drawAction_drawVehicleAsImage(s, getVType().getImgFile(), this, getVType().getWidth() * exaggeration, curCLength)) {
switch (getVType().getGuiShape()) {
case SUMOVehicleShape::TRUCK_SEMITRAILER:
case SUMOVehicleShape::TRUCK_1TRAILER:
if (i == firstCarriageNo) { // at the moment amReversed is only ever set for rail - so has no impact in this call
if (i == trainHelper.getFirstCarriageNo()) { // at the moment amReversed is only ever set for rail - so has no impact in this call
GUIBaseVehicleHelper::drawAction_drawVehicleAsPoly(s, getVType().getGuiShape(), getVType().getWidth() * exaggeration, curCLength, 0, false, reversed);
} else {
GLHelper::setColor(current);
GLHelper::drawBoxLine(Position(0, 0), 180, curCLength, halfWidth);
}
break;
default: {
if (i == firstCarriageNo) {
if (i == trainHelper.getFirstCarriageNo()) {
GLHelper::setColor(darker);
} else {
GLHelper::setColor(current);
Expand All @@ -478,7 +401,7 @@ GUIVehicle::drawAction_drawCarriageClass(const GUIVisualizationSettings& s, bool
glVertex2d(halfWidth - xCornerCut, 0);
glEnd();
// indicate front of the head of the train
if (i == firstCarriageNo) {
if (i == trainHelper.getFirstCarriageNo()) {
glTranslated(0, 0, 0.1);
glColor3d(0, 0, 0);
glBegin(GL_TRIANGLE_FAN);
Expand All @@ -500,8 +423,6 @@ GUIVehicle::drawAction_drawCarriageClass(const GUIVisualizationSettings& s, bool
}
}
GLHelper::popMatrix();
carriageOffset -= (curCLength + carriageGap);
carriageBackOffset -= carriageLengthWithGap;
}
if (getVType().getGuiShape() == SUMOVehicleShape::RAIL_CAR) {
GLHelper::pushMatrix();
Expand All @@ -517,7 +438,7 @@ GUIVehicle::drawAction_drawCarriageClass(const GUIVisualizationSettings& s, bool
glTranslated(front.x(), front.y(), getType());
const double degAngle = RAD2DEG(getAngle() + M_PI / 2.);
glRotated(degAngle, 0, 0, 1);
glScaled(exaggeration, upscaleLength, 1);
glScaled(exaggeration, trainHelper.getUpscaleLength(), 1);
if (mySeatPositions.size() == 0) {
mySeatPositions.push_back(Seat(back, DEG2RAD(angle)));
}
Expand Down Expand Up @@ -785,60 +706,6 @@ GUIVehicle::drawRouteHelper(const GUIVisualizationSettings& s, ConstMSRoutePtr r
}


MSLane*
GUIVehicle::getPreviousLane(MSLane* current, int& furtherIndex) const {
if (furtherIndex < (int)myFurtherLanes.size()) {
return myFurtherLanes[furtherIndex++];
} else {
// try to use route information
int routeIndex = getRoutePosition();
bool resultInternal;
if (MSGlobals::gUsingInternalLanes && MSNet::getInstance()->hasInternalLinks()) {
if (myLane->isInternal()) {
if (furtherIndex % 2 == 0) {
routeIndex -= (furtherIndex + 0) / 2;
resultInternal = false;
} else {
routeIndex -= (furtherIndex + 1) / 2;
resultInternal = false;
}
} else {
if (furtherIndex % 2 != 0) {
routeIndex -= (furtherIndex + 1) / 2;
resultInternal = false;
} else {
routeIndex -= (furtherIndex + 2) / 2;
resultInternal = true;
}
}
} else {
routeIndex -= furtherIndex;
resultInternal = false;
}
furtherIndex++;
if (routeIndex >= 0) {
if (resultInternal) {
const MSEdge* prevNormal = myRoute->getEdges()[routeIndex];
for (MSLane* cand : prevNormal->getLanes()) {
for (MSLink* link : cand->getLinkCont()) {
if (link->getLane() == current) {
if (link->getViaLane() != nullptr) {
return link->getViaLane();
} else {
return const_cast<MSLane*>(link->getLaneBefore());
}
}
}
}
} else {
return myRoute->getEdges()[routeIndex]->getLanes()[0];
}
}
}
return current;
}


double
GUIVehicle::getLastLaneChangeOffset() const {
return STEPS2TIME(getLaneChangeModel().getLastLaneChangeOffset());
Expand Down
6 changes: 0 additions & 6 deletions src/guisim/GUIVehicle.h
Original file line number Diff line number Diff line change
Expand Up @@ -184,12 +184,6 @@ class GUIVehicle : public MSVehicle, public GUIBaseVehicle {
* passengerSeats are computed beginning at firstPassengerCarriage */
void drawAction_drawCarriageClass(const GUIVisualizationSettings& s, bool asImage) const;

/* @brief return the previous lane in this vehicles route including internal lanes
* @param[in] current The lane of which the predecessor should be returned
* @param[in,out] routeIndex The index of the current or previous non-internal edge in the route
*/
MSLane* getPreviousLane(MSLane* current, int& furtherIndex) const;

/// @brief retrieve information about the current stop state
std::string getStopInfo() const;

Expand Down
Loading

0 comments on commit cd28c30

Please sign in to comment.