LCOV - code coverage report
Current view: top level - src/microsim - MSTrainHelper.cpp (source / functions) Coverage Total Hit
Test: lcov.info Lines: 78.5 % 93 73
Test Date: 2024-10-24 15:46:30 Functions: 80.0 % 5 4

            Line data    Source code
       1              : /****************************************************************************/
       2              : // Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
       3              : // Copyright (C) 2001-2024 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              : /****************************************************************************/
      14              : /// @file    MSTrainHelper.cpp
      15              : /// @author  Benjamin Coueraud
      16              : /// @date    Fri, 8 Feb 2024
      17              : ///
      18              : // A class that helps computing positions of a train's carriages.
      19              : /****************************************************************************/
      20              : #include <config.h>
      21              : 
      22              : #include <microsim/MSLane.h>
      23              : #include <microsim/lcmodels/MSAbstractLaneChangeModel.h>
      24              : #include <microsim/MSVehicle.h>
      25              : #include "MSTrainHelper.h"
      26              : 
      27              : 
      28              : const double MSTrainHelper::CARRIAGE_DOOR_WIDTH = 1.5;
      29              : const double MSTrainHelper::PEDESTRIAN_RADIUS_EXTRA_TOLERANCE = 0.01;
      30              : 
      31              : // ===========================================================================
      32              : // method definitions
      33              : // ===========================================================================
      34              : void
      35         4701 : MSTrainHelper::computeTrainDimensions(double exaggeration, int vehicleQuality) {
      36         4701 :     const MSVehicleType& vtype = myTrain->getVehicleType();
      37              :     const double totalLength = vtype.getLength();
      38         4701 :     myUpscaleLength = getUpscaleLength(exaggeration, totalLength, vtype.getWidth(), vehicleQuality);
      39         4701 :     myLocomotiveLength = vtype.getParameter().locomotiveLength * myUpscaleLength;
      40         4701 :     myDefaultLength = vtype.getParameter().carriageLength * myUpscaleLength;
      41         4701 :     if (myLocomotiveLength == 0) {
      42            0 :         myLocomotiveLength = myDefaultLength;
      43              :     }
      44         4701 :     myCarriageGap = vtype.getParameter().carriageGap * myUpscaleLength;
      45         4701 :     myLength = totalLength * myUpscaleLength;
      46         4701 :     myHalfWidth = 0.5 * vtype.getWidth() * exaggeration;
      47         4701 :     myNumCarriages = MAX2(1, 1 + (int)((myLength - myLocomotiveLength) / (myDefaultLength + myCarriageGap) + 0.5)); // Round to closest integer.
      48         4701 :     if (myUpscaleLength > 1 && vehicleQuality != 4) {
      49              :         // at high zoom, it doesn't help to draw many carriages)
      50            0 :         myNumCarriages = MIN2(myNumCarriages, 2);
      51            0 :         myLocomotiveLength = myLength / 2;
      52              :     }
      53              :     assert(myNumCarriages > 0);
      54         4701 :     if (myNumCarriages == 1) {
      55           69 :         myCarriageGap = 0;
      56              :     }
      57         4701 :     myCarriageLengthWithGap = myLength / myNumCarriages;
      58         4701 :     myCarriageLength = myCarriageLengthWithGap - myCarriageGap;
      59         4701 :     myFirstCarriageLength = myCarriageLength;
      60         4701 :     if (myDefaultLength != myLocomotiveLength && myNumCarriages > 1) {
      61         3863 :         myFirstCarriageLength = myLocomotiveLength;
      62         3863 :         myCarriageLengthWithGap = (myLength - myLocomotiveLength) / (myNumCarriages - 1);
      63         3863 :         myCarriageLength = myCarriageLengthWithGap - myCarriageGap;
      64              :     }
      65         4701 :     myCarriageDoors = vtype.getParameter().carriageDoors;
      66         4701 : }
      67              : 
      68              : 
      69              : void
      70         4701 : MSTrainHelper::computeCarriages(bool reversed, bool secondaryShape) {
      71              :     myCarriages.clear();
      72              : 
      73         4701 :     const MSLane* lane = myTrain->getLane(); // Lane on which the carriage's front is situated.
      74         4701 :     int furtherIndex = 0;
      75              :     const MSLane* backLane = lane; // Lane on which the carriage's back is situated.
      76         4701 :     int backFurtherIndex = furtherIndex;
      77              :     // Offsets of front and back parts of a carriage.
      78         4701 :     double carriageOffset = myTrain->getPositionOnLane();
      79         4701 :     if (myTrain->getLaneChangeModel().isOpposite()) {
      80              :         // This still produces some artifacts when not fully on the current lane.
      81            0 :         carriageOffset = MIN2(carriageOffset + myTrain->getLength(), lane->getLength());
      82              :     }
      83         4701 :     double carriageBackOffset = carriageOffset - myFirstCarriageLength;
      84              : 
      85              :     double curCLength = myFirstCarriageLength;
      86         4701 :     myFirstCarriageNo = 0;  // default case - we're going forwards
      87         4701 :     myIsReversed = (myTrain->isReversed() && reversed) || myTrain->getLaneChangeModel().isOpposite();
      88         4701 :     if (myIsReversed) {
      89          887 :         myFirstCarriageNo = myNumCarriages - 1;
      90          887 :         if (myNumCarriages > 1) {
      91          887 :             carriageBackOffset = carriageOffset - myCarriageLength;
      92              :         }
      93              :     }
      94         4701 :     if (myTrain->getVehicleType().getParameter().locomotiveLength == 0) {
      95            0 :         myFirstCarriageNo = -1; // don't draw locomotive
      96              :     }
      97              : 
      98         3863 :     myFirstPassengerCarriage = myDefaultLength == myLocomotiveLength || myNumCarriages == 1
      99         8564 :                                || (myTrain->getVClass() & (SVC_RAIL_ELECTRIC | SVC_RAIL_FAST | SVC_RAIL)) == 0 ? 0 : 1;
     100              : 
     101         4701 :     const double lateralOffset = (myTrain->isParking() && myTrain->getNextStopParameter()->posLat == INVALID_DOUBLE
     102         9402 :                                   ? (myTrain->getLane()->getWidth() * (MSGlobals::gLefthand ? -1 : 1))
     103         4701 :                                   : -myTrain->getLateralPositionOnLane());
     104              : 
     105        19682 :     for (int i = 0; i < myNumCarriages; ++i) {
     106        14981 :         Carriage* carriage = new Carriage();
     107        14981 :         if (i == myFirstCarriageNo) {
     108         4701 :             curCLength = myFirstCarriageLength;
     109         4701 :             if (myFirstCarriageNo > 0) {
     110              :                 // Previous loop iteration has adjusted backpos for a normal carriage so have to correct
     111          887 :                 carriageBackOffset += myCarriageLengthWithGap;
     112          887 :                 carriageBackOffset -= myFirstCarriageLength + myCarriageGap;
     113              :             }
     114              :         } else {
     115        10280 :             curCLength = myCarriageLength;
     116              :         }
     117        15928 :         while (carriageOffset < 0) {
     118          947 :             const MSLane* prev = myTrain->getPreviousLane(lane, furtherIndex);
     119          947 :             if (prev != lane) {
     120          830 :                 carriageOffset += prev->getLength();
     121              :             } else {
     122              :                 // No lane available.
     123              :                 carriageOffset = 0;
     124              :             }
     125              :             lane = prev;
     126              :         }
     127        16263 :         while (carriageBackOffset < 0) {
     128         1282 :             const MSLane* prev = myTrain->getPreviousLane(backLane, backFurtherIndex);
     129         1282 :             if (prev != backLane) {
     130         1022 :                 carriageBackOffset += prev->getLength();
     131              :             } else {
     132              :                 // No lane available.
     133              :                 carriageBackOffset = 0;
     134              :             }
     135              :             backLane = prev;
     136              :         }
     137        14981 :         carriage->front = lane->getShape(secondaryShape).positionAtOffset(carriageOffset * lane->getLengthGeometryFactor(secondaryShape), lateralOffset);
     138        14981 :         carriage->back = backLane->getShape(secondaryShape).positionAtOffset(carriageBackOffset * backLane->getLengthGeometryFactor(secondaryShape), lateralOffset);
     139        14981 :         myCarriages.push_back(carriage);
     140              : 
     141        14981 :         carriageOffset -= (curCLength + myCarriageGap);
     142        14981 :         carriageBackOffset -= myCarriageLengthWithGap;
     143              :     }
     144         4701 : }
     145              : 
     146              : 
     147              : void
     148          336 : MSTrainHelper::computeDoorPositions() {
     149         1560 :     for (Carriage* carriage : myCarriages) {
     150              :         Position dir = carriage->front - carriage->back;
     151              :         const double carriageLength = dir.length2D();
     152         1224 :         if (carriageLength > 0.0) {
     153         1224 :             dir.norm2D();
     154         3672 :             for (int j = 1; j <= myCarriageDoors; j++) {
     155         2448 :                 const double doorOffset = j * carriageLength / (myCarriageDoors + 1);
     156         2448 :                 carriage->doorPositions.push_back(carriage->front - dir * doorOffset);
     157              :             }
     158              :         }
     159              :     }
     160          336 : }
     161              : 
     162              : 
     163              : void
     164            0 : MSTrainHelper::computeUnboardingPositions(double passengerRadius, std::vector<Position>& unboardingPositions) {
     165            0 :     passengerRadius += PEDESTRIAN_RADIUS_EXTRA_TOLERANCE;
     166            0 :     for (Carriage* carriage : myCarriages) {
     167              :         Position dir = carriage->front - carriage->back;
     168              :         const double carriageLength = dir.length2D();
     169            0 :         if (carriageLength > 0.0) {
     170            0 :             dir.norm2D();
     171            0 :             const Position perp = Position(-dir.y(), dir.x());
     172              :             double nbrLongitudinalCells, longitudinalOffset;
     173            0 :             longitudinalOffset = std::modf((carriageLength - 2.0 * passengerRadius) / (2.0 * passengerRadius), &nbrLongitudinalCells);
     174              :             double nbrLateralCells, lateralOffset;
     175            0 :             lateralOffset = std::modf((myHalfWidth * 2.0 - 2.0 * passengerRadius) / (2.0 * passengerRadius), &nbrLateralCells);
     176            0 :             const Position gridOrigin = carriage->back + dir * (passengerRadius + 0.5 * longitudinalOffset) - perp * (myHalfWidth - passengerRadius - 0.5 * lateralOffset);
     177            0 :             for (unsigned int i = 0; i <= (unsigned int)nbrLongitudinalCells; i++) {
     178            0 :                 for (unsigned int j = 0; j <= (unsigned int)nbrLateralCells; j++) {
     179            0 :                     carriage->unboardingPositions.push_back(gridOrigin + dir * i * 2.0 * passengerRadius + perp * j * 2.0 * passengerRadius);
     180              :                 }
     181              :             }
     182              :         }
     183              :         std::copy(carriage->unboardingPositions.begin(), carriage->unboardingPositions.end(), std::back_inserter(unboardingPositions));
     184              :     }
     185              :     // Shuffle the positions upstream so that we don't have to sample later on, just pop the last element.
     186            0 :     RandHelper::shuffle(unboardingPositions);
     187            0 : }
     188              : 
     189              : 
     190              : double
     191      9080201 : MSTrainHelper::getUpscaleLength(double upscale, double length, double width, int vehicleQuality) {
     192      9080201 :     if (upscale > 1 && length > 5 && width < 5 && vehicleQuality != 4) {
     193            0 :         return MAX2(1.0, upscale * 5 / length);
     194              :     } else {
     195              :         return upscale;
     196              :     }
     197              : }
        

Generated by: LCOV version 2.0-1